我正在阅读Oracle的Java Concurrency Tutorial。
还有一个死锁的例子
核心代码:
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());
}
然后,当本教程转到 LockObject 时,它提供了一个解决方案来处理 Lock 对象的死锁。
现在我想知道是否有另一种方法可以在不使用Lock
对象的情况下避免死锁?
避免死锁的一种方法是通过强加获取两个锁的顺序来打破对称性。例如,你可以说,在开始弓时,线应该总是在名字按字母顺序排在第一位的朋友上锁,这样任何做弓的线都必须首先获得阿尔方斯的锁,然后获得加斯顿的锁,永远不要反向:
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());
}
}