以下是直接来自描述死锁的Sun教程的代码。但是我不明白在这种情况下死锁是如何发生的,因为两种方法都是同步的。两个线程如何同时在同一个同步方法中?
死锁描述了两个或多个线程永远被阻塞,等待彼此的情况。这是一个例子。
Alphonse和Gaston是朋友,并且很有礼貌的信徒。严格的礼貌规则是,当你向朋友鞠躬时,你必须保持鞠躬,直到你的朋友有机会归还弓箭。不幸的是,这条规则没有考虑到两个朋友可能同时互相鞠躬的可能性。这个示例应用程序Deadlock模拟了这种可能性:
public class Deadlock {
static class Friend {
private final String name;
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public synchronized void bow(Friend bower) {
System.out.format("%s: %s has bowed to me!%n",
this.name, bower.getName());
bower.bowBack(this);
}
public synchronized void bowBack(Friend bower) {
System.out.format("%s: %s has bowed back to me!%n",
this.name, bower.getName());
}
}
public static void main(String[] args) {
final Friend alphonse = new Friend("Alphonse");
final Friend gaston = new Friend("Gaston");
new Thread(new Runnable() {
public void run() { alphonse.bow(gaston); }
}).start();
new Thread(new Runnable() {
public void run() { gaston.bow(alphonse); }
}).start();
}
}
当Deadlock运行时,两个线程在尝试调用bowBack时极有可能会阻塞。两个块都不会结束,因为每个线程都在等待另一个线程退出弓。
答案 0 :(得分:8)
同步(实例)方法锁定对象,而不是类。
alphonse.bow抓住阿尔方斯和gaston.bow的锁定抓住gaston上的锁。当'alphonse'线程处于低位时,它试图抓住bower.bowBack上'gaston'的锁。同样,'gaston'试图抓住'alphonse'的锁定。为了清晰起见而编辑(我希望):
让我们调用两个线程Thread1和Thread2。
Thread1运行alphonse.bow(gaston),它抓住alphonse对象上的锁,而Thread2运行gaston.bow(alphonse)并抓住gaston对象上的锁。
在Thread1中,当它试图运行bower.bowBack(this)时,bower = gaston,线程需要先获取gaston上的锁。
在这种情况下,Thread2尝试用bower = alphonse做同样的事情。 Thread1有一个Thread2需要的锁,反之亦然,这就是发生死锁的原因。
顺便说一句,不必总是发生死锁。如果Thread1可以在Thread2有机会之前启动和完成(例如,如果在Thread1启动之后但在创建/启动Thread2之前某些东西挂起主线程),则不会发生死锁。