Versions Compared

Key

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

...

Code Block
final class Book {
  // May change its locking policy in the future to use private internal locks
  private final String title;
  private Calendar dateIssued;
  private Calendar dateDue;

  Book(String title, int days) {
    this.title = title; 
  }
  
  public synchronized void issueBookissue(int days) {
    dateIssued = Calendar.getInstance();
    dateDue = Calendar.getInstance();
    dateDue.add(Calendar.DAY_OF_MONTH, days);	 
  }

  public synchronized Calendar getDueDate() {
    return dateDue;
  }
}

...

Code Block
bgColor#FFCCCC
// Client
public class BookWrapper {
  private final Book book;

  BookWrapper(Book book) {
    this.book = book;
  }

  public void issueBookissue(int days) {
    book.issueBookissue();
  }

  public Calendar getDueDate() {
    return book.getDueDate();
  }

  public void renewBookrenew() {
    synchronized(book) {
      if (book.getDueDate().after(Calendar.getInstance())) {
        throw new IllegalStateException("Book overdue");
      } else {
        book.issueBookissue(14);
      }
    }
  }
}

If class Book changes its synchronization policy in the future, the BookWrapper class's locking strategy will silently break. This is because threads that call getDueDate() of class BookWrapper may perform operations on the thread-safe Book using its new locking policy (internal private lock), however, threads that call method renewBookrenew() will always synchronize on the intrinsic lock of the Book instance. Consequently, the implementation will use two different locks.

...

Code Block
bgColor#ccccff
public class BookWrapper {
  private final Book book;
  private final Object lock = new Object();

  BookWrapper(Book book) {
    this.book = book;
  }

  public void issueBookissue(int days) {
    synchronized(lock) {
      book.issueBookissue();
    }
  }

  public Calendar getDueDate() {
    synchronized(lock) {
      return book.getDueDate();
    }
  }

  public void renewBookrenew() {
    synchronized(lock) {
      if (book.getDueDate().after( Calendar.getInstance())) {
        throw new IllegalStateException("Book overdue");
      } else {
        book.issueBookissue(14);
      }
    }
  }
}

Consequently, its locking strategy is independent of the locking policy of the Book instance.

...