活性:一个并发应用的及时执行能力。
这里主要介绍最常见的活性问题:死锁。另外简要介绍其他两种活性问题:饿死、活锁。
1.死锁
当两个线程相互阻塞,一直等待不能正常运行,就造成了死锁。例如,Alphonse 和Gaston是好朋友,他们都非常懂礼貌。当一方向另一方鞠躬时,必须等到对方还礼时才能直起身来。但是如果他们两人同时向对方鞠躬,那么谁也等不到对方还礼,两人就会一直保持鞠躬状态,这就是死锁。当下面的程序运行时,两个线程都会在试图调用bowBack时被阻塞,他们都在等待对方退出bow
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();
}
}
饿死是指一个线程无法访问共享资源,进而无法运行下去。这在共享资源被“贪婪的”线程长期占有的时候会发生。例如,某对象提供了一个同步方法,该方法的返回时间很长,来了一个线程频繁地调用改方法,这时候其他线程若想访问该对象就会被阻塞。
3.活锁
死锁是两个线程一直互相阻塞,一直等待不能运行下去。而活锁是两个线程一直相互响应,导致不能正常运行下去。例如,Alphonse 和Gaston在走廊上迎面走过来,Alphonse 移到左边让Gaston过去, 同时 Gaston 移到右边让Alphonse过去,这时他俩还是互相挡着路。于是Alphone又移到右边, Gaston移到左边,还是互相挡着路,所以……