Home  Synchronization and concurrency  wait/notify  final  volatile  synchronized keyword  Java threading  Deadlock (and avoiding it)  Java 5: ConcurrentHashMap  Atomic variables  Explicit locks  Queues  Semaphores  CountDownLatch  CyclicBarrier

Explicit locks in Java 5 (ctd)

Lock basics

The basic locking paradigm is as follows: we have some Lock object, which we explicitly call a lock method on. When we're finished (i.e. in a finally clause), we explicitly unlock it:

Lock lck = ...

lck.lock();
try {
   ... access shared resource
} finally {
  lck.unlock();
}

As mentioned above, Lock is an interface. The implementation provided is ReentrantLock1. As an example, we'll use a ReentrantLock to implement a simple concurrent integer array. (This is just an example of using locks: in reality, AtomicIntegerArray provides a better performing alternative.)

public class ConcurrentIntegerArray {
  private final Lock lock = new ReentrantLock();
  private final int[] arr;

  public ConcurrentIntegerArray(int size) {
    arr = new int[size];
  }
  public void set(int index, int value) {
    lock.lock();
    try {
      arr[index] = value;
    } finally {
      lock.unlock();
    }
  }
  public int get(int index) {
    lock.lock();
    try {
      return arr[index];
    } finally {
      lock.unlock();
    }
  }
}

In this example, we have an underlying array, arr, and we wrap accesses to this array in a lock/unlock pair. Once thing you may be wondering is about memory access semantics. With regular synchronized blocks, the JVM guarantees that entering and exiting the synchronized block acts as a "memory barrier", meaning that, for example, where a memory write occurs inside the synchronized block, this write cannot be re-ordered to occur after the block is exited (else another thread might not see it). Here, there's no synchronized, so how does it work? Well, it turns out that a contract of the Lock interface is that it provides the same memory barrier behaviour as synchronized. What that basically means is that we can safely use the lock/unlock action as the thing that guarnatees that a write by Thread A will be seen by Thread B.

In case it's not obvious: once we've chosen a Lock as our method of synchronizing access to a particular variable, we should make sure we use only that same lock object for all accesses. In particular, we can't mix synchronization via a Lock with synchronization via synchronized and expect it to work! I mention this mainly because it's an accident that could happen if you are adapting legacy code to use explicit locks instead of synchronized blocks2. (When constructing the object, it is OK to rely on final here to make sure that the arr reference set by one thread is visible to other threads accessing the get/set methods.)

Next...

Now we've seen the basics of using explicit locks, we look at some of the benefits, starting with timed and interruptible locking.


Notes:
1. A lock is said to be re-entrant if the owning thread can call its lock method multiple times without blocking. To release the lock, the owning thread must call the unlock method as many times as it called the lock method.
2. Of course, if you've used good encapsulation, all of the locking needed by a particular class will be internal to that class and it'll be easy to find all the places where synchronized is used, won't it...?

Article written by Neil Coffey (@BitterCoffey).

Software

 LetterMeister (word puzzle game for iPhone)
 Currency Quoter (currency converter/predictor)
 French Vocab Games for iPhone/iPad
 Vocabularium: create Spanish vocab podcasts


Java programming articles and tutorials on this site are written by Neil Coffey (@BitterCoffey). Suggestions are always welcome if you wish to suggest topics for Java tutorials or programming articles, or if you simply have a programming question that you would like to see answered on this site. Most topics will be considered. But in particular, the site aims to provide tutorials and information on topics that aren't well covered elsewhere, or on Java performance information that is poorly described or understood. Suggestions may be made via the Javamex blog (see the site's front page for details).
Copyright © Neil Coffey 2015. All rights reserved.