デッドロックを回避する 1 つの方法は、2 つのロックを取得する順序を強制することによって対称性を破ることです。たとえば、お辞儀を開始するとき、スレッドは常に名前がアルファベット順で最初に来る友人にロックを設定する必要があると言うことができます。そのため、お辞儀をするスレッドは最初にアルフォンスのロックを取得し、次にガストンのロックを取得する必要があります。逆に:
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);
}
デッドロックを回避するもう 1 つの方法は、2 つではなく 1 つのロックを使用することです。1 つのロックをめぐって競合する 2 つのスレッドがデッドロックすることはありません。
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());
}
}