Explicit locks in Java 5

Before Java 5, the language offered two key synchronization facilities: the synchronized keyword allows exclusive locking at the level of a block or method, and in tandem with this locking mechanism, the wait/notify idiom effectively allows threads to wait, interruptably, for a 'signal' from another thread. The standard form of locking provided by the synchronized keyword has limitations:

Of course, it does have the advantage of simple syntax and built-in support from the JVM (people who have stuck to good-old synchronized have seen their tenacity rewarded with gradual performance improvements over the course of several JVM updates). If you need some of the features of the above list, you can 'roll your own' lock with judicious use of wait/notify (for example, some of the Swing text editing code actually uses an implementation of a read/write lock). So we could create a Lock class with the following functionality:

public class Lock {
  /**
   * Waits for up to 'maxWait' milliseconds to acquire the lock,
   * and returns true if the lock was acquired.
   **/
  public boolean acquireLock(int maxWait)
    throws InterruptedException { ... }

  public void releaseLock() { ... }
}

(By the way, if you're wondering how to actually implement this, then see this rough implementation of a lock pre-Java 5.) Such a lock would then be used by the caller as follows:

Lock lck = getDatabaseLock();
if (!lck.acquireLock(2000)) {
  throw new RuntimeException("Couldn't get DB lock in 2 seconds");
}
try {
  ... do interesting thing with database ...
} finally {
  lck.releaseLock();
}

One disadvantage of this locking mechanism (apart from any performance issues2) is the syntax: we have to explicitly deal with lock objects and in particular, we must ensure that we release the lock in a finally clause once we've acquired it. With a regular synchronized block, the compiler takes care of this automatically for us.

But on the plus side, this lock solves some of the problems mentioned above. In particular, it won't wait forever if the lock can't be acquired for some reason. And once our lock is implemented in Java, we can do other interesting things with it, such as build in performance monitoring.

Locks in Java 5

Well, all this introduction wasn't intended to make you run away and write a new lock class. Java 5 already introduces classes with functionality similar to the example Lock class above. But they call on the new atomic variable access facilities of Java 5 to create more efficient, scalable versions than were previously possible. They are also fuller implementations, dealing with some issues (in particular fairness) which we don't attempt to deal with in our simple example.

So, on the next page, we look at explicit lock classes in Java 5.


1. There is a bad way: you could set which object gets synchronized on at runtime, and to mean "don't synchronize", you can synchronize on new Object().
2. For what it's worth, the simple implementation I give performs about two times worse than regular Java synchronization. That is, in a simple test of contended array access, we get about half as much throughput synchronizing using this lock implementation as opposed to regular synchronized lock. Contrast this with Java 5's Lock implementations which generally offer better (or at least, no worse) throughput than synchronized and still offer interruptability. Of course, if you really need interruptable locking and you really can't move to Java 5, half the throughput may be a price worth paying, and this example can doubtless be improved a little.


Written by Neil Coffey. Copyright © Javamex UK 2008. All rights reserved.