Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added a ReentrantLock CS

...

Unlike the previous compliant solution, this solution incurs no performance penalty, as multiple transfers can occur concurrently as long as the transfers involve distinct target accounts.

Compliant Solution (ReentrantLock)

In this compliant solution, each BankAccount has a java.util.concurrent.locks.ReentrantLock associated with it. This permits the depositAllAmount() method to try acquiring both accounts' locks, but releasing its locks if it fails, and trying again later.

Code Block
bgColor#FFcccc

class BankAccount {
  private int balanceAmount;  // Total amount in bank account
  private final Lock lock = new ReentrantLock();
  Lock getLock() {return lock;}
  private static final int TIME = 1000; // ms
	 
  private BankAccount(int balance) {
    this.balanceAmount = balance;
  }

  // Deposits the amount from this object instance to BankAccount instance argument ba 
  private void depositAllAmount(BankAccount ba) {
    while (true) {
      if (this.lock.tryLock()) {
        try {
          if (ba.lock.tryLock()) {
            try {
              ba.balanceAmount += this.balanceAmount;
              this.balanceAmount = 0; // withdraw all amount from this instance
              ba.displayAllAmount();  // Display the new balanceAmount in ba (may cause deadlock)
              break;
            } finally {
              ba.getLock().unlock();
            }
          }
        } finally {
          this.getLock().unlock();
        }
      }
      sleep( TIME);
    }
  }
  
  private void displayAllAmount() {
    while (true) {
      if (lock.tryLock()) {
        try {
          System.out.println(balanceAmount);
          break;
        } finally {
          lock.unlock();
        }
      }
      sleep( TIME);
    }
  }

  public static void initiateTransfer(final BankAccount first, final BankAccount second) {
    Thread t = new Thread(new Runnable() {
      public void run() {
        first.depositAllAmount(second);
      }
    });
    t.start();
  }
}

Deadlock is impossible in this code, becase no routine grabs a lock and holds it indefinitely. If a lock is acquired, but the system cannot proceed immediately, it releases the lock and sleeps before trying the lock again.

Code that uses this lock behaves similar to synchronized code that uses the traditional monitor lock. ReentrantLock provides several other capabilities, for instance, the tryLock() method does not block waiting if another thread is already holding the lock. The class java.util.concurrent.locks.ReentrantReadWriteLock can be used when some thread requires a lock to write information while other threads require the lock to concurrently read the information.

Noncompliant Code Example

...