下面是直接来自描述死锁的 Sun 教程的代码。但是,考虑到两种方法都是同步的,我不明白在这种情况下如何发生死锁。两个线程如何同时在同一个同步方法中?
死锁描述了两个或多个线程永远阻塞,互相等待的情况。这是一个例子。
Alphonse 和 Gaston 是 friend ,而且非常讲究礼貌。一个严格的礼貌规则是,当你向 friend 鞠躬时,你必须一直鞠躬,直到你的 friend 有机会还礼。不幸的是,这条规则没有考虑到两个 friend 可能同时互相鞠躬的可能性。这个示例应用程序 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();
}
}
当死锁运行时,两个线程极有可能在尝试调用 bowBack 时阻塞。两个 block 都不会结束,因为每个线程都在等待另一个线程退出 bow。
最佳答案
同步(实例)方法锁定对象,而不是类。
alphonse.bow 获取了 alphonse 的锁,gaston.bow 获取了 gaston 的锁。当“alphonse”线程处于 bow 状态时,它会尝试在 bower.bowBack 上获取“gaston”上的锁。同样,“gaston”试图获取“alphonse”的锁。
为清楚起见编辑(我希望):
我们称这两个线程为 Thread1 和 Thread2。
Thread1 运行 alphonse.bow(gaston),它在其中获取 alphonse 对象的锁,而 Thread2 运行 gaston.bow(alphonse) 并获取 gaston 对象的锁。
在 Thread1 中,当它尝试运行 bower.bowBack(this) 时,其中 bower = gaston,线程需要首先获取 gaston 上的锁。
在此过程中,线程 2 尝试使用 bower = alphonse 做同样的事情。 Thread1 有 Thread2 需要的锁,反之亦然,这就是发生死锁的原因。
顺便说一句,死锁不一定总是会发生。如果 Thread1 可以在 Thread2 有机会这样做之前启动和完成(例如,如果在 Thread1 启动之后但在创建/启动 Thread2 之前挂起主线程),则不会发生死锁。
关于java - Sun教程中关于死锁的一个问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2270930/