日期:2014-05-20  浏览次数:20782 次

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());
}