Use finally to unlock

Sometimes Lock objects are used to control access to mutable data in a multithreaded environment. When a thread is finished with the data, you must ensure the lock is released.

Brian Goetz in Java Concurrency in Practice strongly recommends the following technique for ensuring that a lock is released. It uses a try..finally style; this ensures that no matter what happens during the time the lock is held, it will eventually be unlocked. Even if an unexpected RuntimeException is thrown, the lock will still be released.

Lock myLock = ...
myLock.lock();
try {
  //interact with mutable data
}
finally{
  myLock.unlock();
}

Here's an example which follows the above pattern, with a read-write lock.


import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
  User preferences, using a read-write lock. 
  
 <P>The context: preference information is read in upon startup.
 The config data is 'read-mostly': usually, a caller simply reads the 
 information. It gets updated only occasionally. 
 
 <P>Using a read-write lock means that multiple readers can access the 
 same data simultaneously. If a single writer gets the lock, however, then 
 all other callers (either reader or writer) will block until the lock is 
 released by the writer.
 
  <P>(In practice, Brian Goetz reports that the implementation of ConcurrentHashMap 
  is so good that it would likely suffice in many cases, instead of a read-write lock.)
*/
public final class Preferences {
  
  /** Fetch a setting - this is the more common operation.  */
  public String fetch(String aName){
    String result = "";
    fReadLock.lock();
    try {
      result = fPreferences.get(aName);
    }
    finally {
      fReadLock.unlock();
    }
    return result;
  }
 
  /** Change a setting - this is the less common operation. */
  public void update(String aName, String aValue){
    fWriteLock.lock();
    try {
      fPreferences.put(aName, aValue);
    }
    finally {
      fWriteLock.unlock();
    }
  }
 
  //...elided
  
  // PRIVATE
  
  /** Holds the preferences as simple name-value pairs of Strings. */
  private final Map<String, String> fPreferences = new LinkedHashMap<>();
  private final ReentrantReadWriteLock fLock = new ReentrantReadWriteLock();
  private final Lock fReadLock = fLock.readLock();
  private final Lock fWriteLock = fLock.writeLock();
}
 


See Also :
Finally and catch
Read-write locks
Would you use this technique?
Yes   No   Undecided   
© 2014 Hirondelle Systems | Source Code | Contact | License | RSS
Individual code snippets can be used under this BSD license - Last updated on September 21, 2013.
Over 2,000,000 unique IPs last year - Built with WEB4J.
- In Memoriam : Bill Dirani -