关于Java中死锁情况的问题
我正在学习Java中的死锁问题,并且有Sun官方教程中的示例代码:
阿尔方斯和加斯顿是朋友,也是很好的礼节。 严格的礼貌规则是,当你向朋友鞠躬时,你必须保持鞠躬,直到你的朋友有机会归还弓。 不幸的是,这条规则没有考虑到两个朋友可能同时向对方低头的可能性。
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();
}
}
Sun的解释是:
当Deadlock运行时,两个线程在尝试调用bowBack时都会阻塞。 这两个块都不会结束,因为每个线程都在等待另一个线程退出低头。
我似乎不太喜欢。 当alphonse.bow(gaston)运行时,弓法被锁定。 所以现在它会首先打印出“加斯东向我鞠躬!”。 然后它会继续打电话给bowBack,并锁定bowback。 这怎么会导致死锁? 我误解了一个同步方法被调用时会发生什么?
如果有人能给我一个简单的解释,谢谢。
需要注意的一点是,它不是被锁定的方法,而是对象实例。
当你打电话给alphonse.bow(gaston)
,它会尝试获取alphonse
的锁定。 一旦有锁,它会打印一条消息,然后调用gaston.bowBack(alphonse)
。 此时,它试图获得gaston
的锁定。 一旦它有锁,它将打印一条消息,然后释放锁,最后释放alphonse
上的锁。
在死锁中,锁是按照这样的顺序获取的,即任何线程都无法继续进行。
alphonse
锁定 gaston
上的gaston
gaston
锁定 - 不能,因为线程2已经拥有它。 alphonse
锁 - 不能,因为线程1已经拥有它。 阿方斯和加斯顿是两个不同的对象。 每个对象都有一个与之关联的内部监视器(锁)。
可能会发生这样的情况:
alphonse被创建。 他的对象监视器是1。
gaston被创建。 他的对象监视器是2。
alphonse.bow(Gaston)的; alphonse现在拥有锁定#1
gaston.bow(阿方); gaston现在拥有锁定#2
alphonse在gaston上叫bowback并正在等待lock#2 gaston在alphonse上叫bowback并正在等待锁#1
合理? 使用同步关键字锁定实例在方法的持续时间内监视。 这个例子可以改写如下:
public class Deadlock {
static class Friend {
private final String name;
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void bow(Friend bower) {
synchronized(this) {
System.out.format("%s: %s has bowed to me!%n",
this.name, bower.getName());
bower.bowBack(this);
}
}
public void bowBack(Friend bower) {
synchronized(this) {
System.out.format("%s: %s has bowed back to me!%n",
this.name, bower.getName());
}
}
}
}
锁定在Java对象上,而不是Java方法。 所以当在一个方法上使用synchronized时,它会锁定“this”对象。 在静态方法的情况下,它锁定类对象。
您可以使用synchronized ( object ) { }
显式指定监视器对象。