避免死锁的一种方法是通过强制获取两个锁的顺序来破坏对称性。例如,您可能会说,在启动弓箭时,线程应该始终锁定名字按字母顺序排在第一位的朋友,因此任何做弓箭的线程都必须先获得 Alphonse 的锁,然后再获得 Gaston 的锁,从不相反:
public void bow(Friend bower) {
Friend lock = (this.name.compareTo(bower.name)<0)? this : bower);
synchronized (lock) {
System.out.format("%s: %s has bowed to me!%n", this.name, bower.getName());
bower.bowBack(this);
}
}
public void bowBack(Friend bower) {
Friend lock = (this.name.compareTo(bower.name)>0)? this : bower);
synchronized (lock) {
System.out.format("%s: %s has bowed back to me!%n", this.name, bower.getName());
}
}
无锁选项是使用原子变量来表示弓是否已经在进行中,如果有弓则等待:
private static AtomicBoolean bowing = new AtomicBoolean();
public void bow(Friend bower) {
while (!bowing.compareAndSet(false, true)) Thread.yield();
System.out.format("%s: %s has bowed to me!%n", this.name, bower.getName());
bower.bowBack(this);
bowing.set(false);
}
避免死锁的另一种方法是使用单个锁而不是两个。竞争一个锁的两个线程不能死锁。
private static Object lock = new Object();
public void bow(Friend bower) {
synchronized (lock) {
System.out.format("%s: %s has bowed to me!%n", this.name, bower.getName());
bower.bowBack(this);
}
}
public void bowBack(Friend bower) {
synchronized (lock) {
System.out.format("%s: %s has bowed back to me!%n", this.name, bower.getName());
}
}