by Uwe B. Meding

Developing multi-threaded code has always been a non-trivial undertaking.  The ReadWriteLock is the typical mechanism used  to help minimize thread waits when accessing shared resources. It lets you separate the code into sections that need to be mutually exclusive (writers), and sections that don’t (readers).

The issue with ReadWriteLock is that it can be very slow (up to 10x), which kind of defeats its purpose. Java 8 introduces a new read/write lock – called StampedLock. It has a number of methods that support extremely fast locking. One of the drawbacks of stamped locks is that they re not as straightforward to use as the heavy traditional lock. It’s also not re-entrant, which means a thread can deadlock against itself.

StampedLock has an “optimistic” mode that issues a handle (“stamp”) that is returned by each locking operation; each unlock operation releases its correlating stamp. Any thread that acquires a write lock while a reader was holding an optimistic lock, will cause the optimistic unlock to be invalidated (the stamp is no longer valid). The application can then retry the same operation, or attempt a heavier lock. For example, here is a snippet of an application that attempts to use a fast lock first, and if the operation fails, attempts to use a heavy read lock.

StampedLock lock = new StampedLock();
// try the fast (non-blocking) lock first
long stamp = 0L;
try {
  stamp = lock.tryOptimisticRead();

  doSomeWork();

  if (lock.validate(stamp)) {
   // Great! no contention, the work was successful
  } else {
    // another thread acquired a write lock while we were doing some work, 
    // repeat the operation using the heavy (blocking) lock
    stamp = lock.readLock();

    doSomeWork();
  }
} finally {
  // release the lock stamp
  if (stamp != 0L) {
    lock.unlock(stamp);
  }
}

Leave a Reply