我正在阅读Java Concurrency in Practice并且坚持这个程序,作者说它不会导致死锁。但是,如果我交换方法参数,那么它将导致死锁。
Obj1 = hash-code =1
Obj2 = hash-code =2
Thread1. transfer(Obj1, Obj2)
将从来自theAcct锁定并等待toAcct lock
Thread2.transfer(Obj2, Obj1)
将锁定toAcct并等待fromAcct lock
所以基本上我们最终陷入了死锁。
我的问题是如何在以下代码中避免死锁。
public class InduceLockOrder {
private static final Object tieLock = new Object();
public void transferMoney(final Account fromAcct,
final Account toAcct,
final DollarAmount amount)
throws InsufficientFundsException {
class Helper {
public void transfer() throws InsufficientFundsException {
if (fromAcct.getBalance().compareTo(amount) < 0)
throw new InsufficientFundsException();
else {
fromAcct.debit(amount);
toAcct.credit(amount);
}
}
}
int fromHash = System.identityHashCode(fromAcct);
int toHash = System.identityHashCode(toAcct);
if (fromHash < toHash) {
synchronized (fromAcct) {
synchronized (toAcct) {
new Helper().transfer();
}
}
} else if (fromHash > toHash) {
synchronized (toAcct) {
synchronized (fromAcct) {
new Helper().transfer();
}
}
} else {
synchronized (tieLock) {
synchronized (fromAcct) {
synchronized (toAcct) {
new Helper().transfer();
}
}
}
}
}
interface DollarAmount extends Comparable<DollarAmount> {
}
interface Account {
void debit(DollarAmount d);
void credit(DollarAmount d);
DollarAmount getBalance();
int getAcctNo();
}
class InsufficientFundsException extends Exception {
}
}
答案 0 :(得分:0)
您的示例表明它实际上是正确的。
案例1:Thread1.transfer(Obj1, Obj2)
在这种情况下,fromHash < toHash
因此第一个锁定位于fromAcct
参数或Obj1
,第二个锁定位于toAcct
参数或Obj2
< / p>
案例2:Thread1.transfer(Obj2, Obj1)
在这种情况下,fromHash > toHash
因此第一个锁定位于toAcct
参数或Obj1
,第二个锁定位于fromAcct
参数或Obj2
< / p>
锁定顺序相同,因此不会发生死锁。