Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

This noncompliant code example shows a subtle deadlock issue that manifests itself when synchronization is implemented incorrectly. Assume that an attacker has two bank accounts and is capable of requesting two amount transfer operations in succession. This corresponds to two threads as shown in main(). Objects a and b are constructed such that the amount will be transferred from a to b by first depositing the amount from a to b and then zeroing out a (and vice-versa during the call to b.deposit()).

An insidious deadlock condition can sometimes arise. Both the threads invoke the synchronized deposit method on objects a and b respectively and there is no interleaving of locks. However, the deposit method is designed to request a lock on object a for the first thread and object b for the second. If both threads have acquired separate locks together and the call to withdraw() requests an already held lock, there is a deadlock situation. In case Thread 1 finishes executing before Thread 2, there would not be any issues. Sequences where the threads alternate, such as, T1, T2, T1, T2 can result in a deadlock (In Tx = , 'x' denotes Thread number).

Code Block
bgColor#FFcccc
class BadLocks {
  private int balance;  // Total amount
	 
  private BadLocks(int balance) {
    this.balance = balance;
  }

  private synchronized void withdraw(BadLocks bl) {
    System.out.println("Withdrawing amount...");
    this.balance = 0; 
  }

  private synchronized void deposit(BadLocks bl) {
    System.out.println("Depositing amount...");
    bl.balance += this.balance;
    bl.withdraw(bl);
  }

  public static void main(String[] args) throws Exception {
    final BadLocks a = new BadLocks(5000);
    final BadLocks b = new BadLocks(6000);
		
    // These two threads correspond to two malicious requests triggered by the attacker
    Thread t1 = new Thread(new Runnable() {
      public void run() {
        a.deposit(b);
      }
    });
 
    Thread t2 = new Thread(new Runnable() {
      public void run() {
        b.deposit(a);
      }
    });
    t1.start();
    t2.start();
  }
}

...