Java中的死锁问题 在Java tutorial中的经典问题 Alphonse 和 Gaston 是好朋友。下面是程序。
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();
}
}
这个不是已经synchronized了吗?为什么第二个线程还能抢占进来。如何修改才能解开死锁这个问题呢?谢谢
------解决方案--------------------
首先,假设alphonse线程先获得CPU权限执行
alphonse会调用
alphonse.bow(gaston); 此时,alphonse对象被锁住 --1
而bow方法里,会调用
bower.bowBack(this); --A 这里的bower就是参数gaston,this就是alphonse
假设在调用--A之前,gaston线程获得CPU权限而执行
那么gaston会调用gaston.bow(alphonse); 此时,gaston对象被锁住 --2
而bow方法里,会调用
bower.bowBack(this); --B 这里的bower就是参数alphonse,this就是gaston
假设这个时候alphonse获得CPU权限继续执行--A,因为gaston对象被锁住,所以--A要等待gaston对象的锁被释放,而要释放gaston对象锁,就需要gaston线程执行的gaston.bow(alphonse); 方法结束(即--2结束),而该方法中调用--B,--B要执行就需要获得alphonse对象锁,而alphonse对象锁被--1锁住,这样就造成--1要调用结束就要等待--2,而--2要调用结束就要等待--1,也就是造成死锁
解决方法很多,主要是看你想怎么做,只要避开互相等待对方的锁就可以了
最简单的做法就是两个方法都去掉synchronized,因为这里并不是一个线程调用一个方法,另一个调用另一个方法,也就是说,两个线程都是直接调用相同的一个方法,而且方法属于不同的对象,所以没必要严格的把两个方法对同一个对象同步,如果目的是想把两个方法串行,即所谓的两个方法的打印同步,那么可以锁住相同的一个对象就可以了
比如
Java code
public void bow(Friend bower) {
synchronized(Deadlock.class) { //两个线程锁同一个对象,这里偷懒,作为例子直接锁类对象
System.out.format("%s: %s has bowed to me!%n",
this.name, bower.getName());
bower.bowBack(this);
}
}
public void bowBack(Friend bower) { //这里可以不要synchronized
//或者可以跟上面一样shchronized(Deadlock.class),
//因为线程不直接调用这个方法,所以上面的方法锁住了,这里也就自然同步了,所以synchronized可不要
System.out.format("%s: %s has bowed back to me!%n",
this.name, bower.getName());
}