避免死锁的一种方法是通过强制获取两个锁的顺序来打破对称性。例如,你可以说,当开始一个弓时,线程应该总是锁定一个名字以字母顺序排在第一位的朋友,这样任何做弓的线程都必须首先获得对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());
}
}
执行'Lock'行为。 –
这是唯一的选择吗? – hguser
您需要一种超时尝试获取监视器的机制。我认为'Lock'实现使用了一些'sun.misc.Unsafe'逻辑。 –