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);
        }
      }//inner synchronized
    }
  }//method

方法2:使用轮询锁和定时锁

public boolean transferMoneyWithTryLock(Account fromAccount, Account toAccount, DollarAmount amount)
            throws InsufficientAmountException, InterruptedException {

        // we are defining a stopTime
        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);
        }//while
    }

    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

  1. Avoid synchronization deadlocks

results matching ""

    No results matching ""