Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: changed to package-private ctor so callers can create objects

...

Code Block
bgColor#FFcccc
final class BankAccount {
  private double balanceAmount;  // Total amount in bank account
		 
  private BankAccount(double balance) {
    this.balanceAmount = balance;
  }

  // Deposits the amount from this object instance to BankAccount instance argument ba 
  private void depositAmount(BankAccount ba, double amount) {
    synchronized (this) {
      synchronized(ba) {
        if(amount > balanceAmount) {
          throw new IllegalArgumentException("Transfer cannot be completed");
        }
        ba.balanceAmount += amount;
        this.balanceAmount -= amount; 
      }
    } 
  }
	  
  public static void initiateTransfer(final BankAccount first,
    final BankAccount second, final double amount) {

    Thread t = new Thread(new Runnable() {
      public void run() {
        first.depositAmount(second, amount);
      }
    });
    t.start();
  }
}

...

Code Block
bgColor#ccccff
final class BankAccount {
  private double balanceAmount;  // Total amount in bank account	 
  private static final Object lock = new Object();

  private BankAccount(double balance) {
    this.balanceAmount = balance;
  }

  // Deposits the amount from this object instance to BankAccount instance argument ba 
  private void depositAmount(BankAccount ba, double amount) {
    synchronized (lock) {
      if (amount > balanceAmount) {
        throw new IllegalArgumentException("Transfer cannot be completed");
      }
      ba.balanceAmount += amount;
      this.balanceAmount -= amount; 
    } 
  }
  
  public static void initiateTransfer(final BankAccount first,
    final BankAccount second, final double amount) {

    Thread t = new Thread(new Runnable() {
      public void run() {
        first.depositAmount(second, amount);
      }
    });
    t.start();
  }
}

...

Code Block
bgColor#ccccff
final class BankAccount implements Comparable<BankAccount> {
  private double balanceAmount;  // Total amount in bank account	 
  private final Object lock;

  private final long id; // Unique for each BankAccount
  private static long nextID = 0; // Next unused id

  private BankAccount(double balance) {
    this.balanceAmount = balance;
    this.lock = new Object();
    this.id = this.nextID++;
  }

  public int compareTo(BankAccount ba) {
    // No need to check for overflow because the type long is large
    // enough to hold the required number of bank accounts
    return (this.id - ba.id); 
  }

  // Deposits the amount from this object instance to BankAccount instance argument ba 
  public void depositAmount(BankAccount ba, double amount) {
    BankAccount former, latter;
    if (compareTo(ba) < 0) {
      former = this;
      latter = ba;
    } else {
      former = ba;
      latter = this;
    }
    synchronized (former) {
      synchronized (latter) {
        if (amount > balanceAmount) {
          throw new IllegalArgumentException("Transfer cannot be completed");
        }
        ba.balanceAmount += amount;
        this.balanceAmount -= amount; 
      } 
    }
  }
 
  public static void initiateTransfer(final BankAccount first,
    final BankAccount second, final double amount) {
   
    Thread t = new Thread(new Runnable() {
      public void run() {
        first.depositAmount(second, amount);
      }
    });
    t.start();
  }
}

...

Code Block
bgColor#ccccff
final class BankAccount {
  private double balanceAmount;  // Total amount in bank account
  private final Lock lock = new ReentrantLock();
  private final Random number = new Random(123L);
	 
  private BankAccount(double balance) {
    this.balanceAmount = balance;
  }

  // Deposits the amount from this object instance to BankAccount instance argument ba 
  private void depositAmount(BankAccount ba, double amount) throws InterruptedException {
    while (true) {
      if (this.lock.tryLock()) {
        try {
          if (ba.lock.tryLock()) {
            try {
              if (amount > balanceAmount) {
                throw new IllegalArgumentException("Transfer cannot be completed");
              }
              ba.balanceAmount += amount;
              this.balanceAmount -= amount; 
              break;
            } finally {
              ba.lock.unlock();
            }
          }
        } finally {
          this.lock.unlock();
        }
      }
      int n = number.nextInt(1000);
      int TIME = 1000 + n; // 1 second + random delay to prevent livelock
      Thread.sleep(TIME);
    }
  }
  
  public static void initiateTransfer(final BankAccount first, 
    final BankAccount second, final double amount) {

    Thread t = new Thread(new Runnable() {
      public void run() {
        try {
          first.depositAmount(second, amount);
        } catch (InterruptedException e) {
          Thread.currentThread().interrupt(); // Reset interrupted status
        }
      }
    });
    t.start();
  }
}

...