Versions Compared

Key

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

...

Additionally, synchronization should be limited to cases where it is absolutely necessary. For example, the paint(), dispose(), stop(), and destroy() methods should never be synchronized in an applet because they are always called and used from dedicated threads. The Furthermore, the Thread.stop() and Thread.destroy() methods are deprecated. See ; see rule THI05-J. Do not use Thread.stop() to terminate threads for more information.

...

Code Block
bgColor#FFcccc
final class BankAccount {
  private double balanceAmount;  // Total amount in bank account

  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 transfer = new Thread(new Runnable() {
        public void run() {
          first.depositAmount(second, amount);
        }
    });
    transfer.start();
  }
}

...

Unlike the previous compliant solution, this solution permits multiple concurrent transfers as long as the transfers involve distinct target accounts.

Compliant Solution (ReentrantLock)

...

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);

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

  // Deposits 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 transfer = new Thread(new Runnable() {
        public void run() {
          try {
            first.depositAmount(second, amount);
          } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // Reset interrupted status
          }
        }
    });
    transfer.start();
  }
}

...

Code that uses this locking strategy has behavior similar to that of synchronized code that uses the traditional monitor lock. ReentrantLock also provides several other capabilities. For example, the tryLock() method never blocks waiting immediately returns false when another thread already holds the lock. Further, the java.util.concurrent.locks.ReentrantReadWriteLock class has multiple-reader/single-writer semantics and is useful when some threads require a lock to write information while other threads require the lock to concurrently read the information.

...

Locking on the last element of the vector in addWebRequest() is unnecessary for two reasons: (1) . First, the locks are acquired in increasing order in all the methods. Second, and (2) updates to the vector are reflected in the results of the computations.

...

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="ed5fb63e6fe8438f-fc946076-44f64f1f-b41fbb5b-3e68d9cc40e3c909756675f1"><ac:plain-text-body><![CDATA[

[[JLS 2005

AA. Bibliography#JLS 05]]

[Chapter 17, Threads and Locks

http://java.sun.com/docs/books/jls/third_edition/html/memory.html]

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="da123891d1678822-dc1c80b1-45b6450e-aed096e9-cff752936321bdc38dd823b6"><ac:plain-text-body><![CDATA[

[[Halloway 2000

AA. Bibliography#Halloway 00]]

 

]]></ac:plain-text-body></ac:structured-macro>

...