ade lock manually rwl.readLock().unlock(); // must unlock first to obtain writelock rwl.writeLock().lock(); if (!cacheValid) { // recheck data = ... cacheValid = true; } // downgrade lock rwl.readLock().lock(); // reacquire read without giving up write lock rwl.writeLock().unlock(); // unlock write, still hold read } use(data); rwl.readLock().unlock(); } } ReentrantReadWriteLocks can be used to improve concurrency in some uses of some kinds of Collections. This is typically worthwhile only when the collections are expected to be large, accessed by more reader threads than writer threads, and entail operations with overhead that outweighs synchronization overhead. For example, here is a class using a TreeMap that is expected to be large and concurrently accessed.
class RWDictionary { private final Map<String, Data> m = new TreeMap<String, Data>(); private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private final Lock r = rwl.readLock(); private final Lock w = rwl.writeLock(); public Data get(String key) { r.lock(); try { return m.get(key); } finally { r.unlock(); } } public String[] allKeys() { r.lock(); try { return m.keySet().toArray(); } finally { r.unlock(); } } public Data put(String key, Data value) { w.lock(); try { return m.put(key, value); } finally { w.unlock(); } } public void clear() { w.lock(); try { m.clear(); } finally { w.unlock(); } } }
Implementation Notes
A reentrant write lock intrinsically defines an owner and can only be released by the thread that acquired it. In contrast, in this implementation, the read lock has no concept of ownership, and there is no requirement that the thread releasing a read lock is the same as the one that acquired it. However, this property is not guaranteed to hold in future implementations of this class.
This lock supports a maximum of 65536 recursive write locks and 65536 read locks. Attempts to exceed these limits result in {@link Error} throws from locking methods.
@since 1.5
@author Doug Lea