BankAccount---转账问题
如何避免死锁?
- 最好能避免一次获取多个锁;
- 如果要获取多个锁,要有一种策略确保获取锁的锁的顺序是一致的、确定的;
- 文档中记录锁获取策略。
方法1:使用确定的顺序获取锁:
public void transferMoney(Account fromAccount,
Account toAccount,
DollarAmount amountToTransfer) {
Account firstLock, secondLock;
if (fromAccount.accountNumber() == toAccount.accountNumber())
throw new Exception("Cannot transfer from account to itself");
else if (fromAccount.accountNumber() < toAccount.accountNumber()) {
firstLock = fromAccount;
secondLock = toAccount;
} else {
firstLock = toAccount;
secondLock = fromAccount;
}
synchronized (firstLock) {
synchronized (secondLock) {
if (fromAccount.hasSufficientBalance(amountToTransfer) {
fromAccount.debit(amountToTransfer);
toAccount.credit(amountToTransfer);
}
}
}
}
方法2:使用轮询锁和定时锁
public boolean transferMoneyWithTryLock(Account fromAccount, Account toAccount, DollarAmount amount)
throws InsufficientAmountException, InterruptedException {
final long stopTime = System.nanoTime() + 5000;
while (true) {
if (fromAccount.lock.tryLock()) {
try {
if (toAccount.lock.tryLock()) {
try {
if (!fromAccount.hasSufficientBalance(amountToTransfer)) {
throw new InsufficientAmountException("Insufficient Balance");
} else {
fromAccount.debit(amount);
toAccount.credit(amount);
}
} finally {
toAccount.lock.unlock();
}
}
} finally {
fromAccount.lock.unlock();
}
}
if(stopTime - System.nanoTime() <= 0L)
return false;
Thread.sleep(100);
}
}
class Account {
public Lock lock;
void debit(DollarAmount d) {
}
void credit(DollarAmount d) {
}
DollarAmount getBalance() {
return null;
}
public boolean hasSufficientBalance(DollarAmount amountToTransfer){
}
}
class InsufficientFundsException extends Exception {
}
References
- Avoid synchronization deadlocks