任何人都可以解释为什么这段代码中存在死锁.谢谢
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();
}
}
Run Code Online (Sandbox Code Playgroud)
pol*_*nts 25
考虑以下:
run() { alphonse.bow(gaston); }run() { gaston.bow(alphonse); }alphonse.bow(gaston);,alphonse因为bow()是锁定synchronizedgaston.bow(alphonse);,gaston因为bow()是锁定synchronizedbower.bowBack(this);求值为gaston.bowBack(alphonse);
gaston当前由Thread2持有的锁bower.bowBack(this);求值为alphonse.bowBack(gaston);
alphonse,目前持有线程1问题是synchronized目前存在过多的问题.有很多方法可以"修复"这个问题; 这是一个有益的解决方案:
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 synchronized void bowBack(Friend bower) {
System.out.format("%s: %s has bowed back to me!%n",
this.name, bower.getName());
}
Run Code Online (Sandbox Code Playgroud)
现在bowBack()完全synchronized,但bow()只是synchronized部分,使用synchronized(this)语句.这样可以防止死锁.
以下是Effective Java 2nd Edition的引用,第67项:避免过度同步
为避免活动和安全故障,请勿在
synchronized方法或块中将控制权交给客户.换句话说,在synchronized区域内,不要调用设计为被覆盖的方法,或者由客户端以函数对象的形式提供的方法.从class与synchronized地区的角度来看,这种方法是陌生的.该类不知道该方法的作用,也无法控制它.根据外来方法的作用,从synchronized区域调用它可能会导致异常,死锁或数据损坏.[...]作为一项规则,你应该在
synchronized区域内做尽可能少的工作.获取锁定,检查共享数据,必要时进行转换,然后取消锁定.
本质上,bower.bowBack(this)是试图将控制权交给外来方法,因为bowBack()它不是一种final方法class Friend.请考虑以下尝试解决问题,例如:
// attempt to fix: STILL BROKEN!!!
public synchronized void bow(Friend bower) {
System.out.format("%s: %s has bowed to me!%n",
this.name, bower.getName());
bower.bowBack(this);
// ceding control to alien method within synchronized block!
}
// not a final method, subclasses may @Override
public void bowBack(Friend bower) {
System.out.format("%s: %s has bowed back to me!%n",
this.name, bower.getName());
}
Run Code Online (Sandbox Code Playgroud)
上面的代码不会与当前alphonse/gaston场景死锁,但是由于bow()将控制权转移到非final方法bowBack(),因此子类可以@Override以导致bow()死锁的方式使用该方法.即,bowBack()是一种外来到方法bow(),因此应当NOT已经从内调用synchronized区域.
Nik*_*bak 13
这是它可能会被执行的方式.
alphonse.bow(gaston);,alphonse现在由于synchronized关键字而被锁定gaston.bow(alphonse);,gaston现已锁定bower.bowBack(this);从第一次bow方法调用执行,因为gaston(bower)被锁定.等待锁被释放.bower.bowBack(this);从第二次bow方法调用执行.等待锁被释放.两个线程都互相等待释放锁定.
| 归档时间: |
|
| 查看次数: |
2136 次 |
| 最近记录: |