ReentrantReadWriteLock usage (rotation)

Turn from https://blog.51cto.com/viphyy/2092670

The so-called read-write lock refers to the shared lock and exclusive lock for accessing resources. The general reentry semantics is that if a write lock is added to a resource, other threads can no longer obtain the write lock and read lock, but the thread holding the write lock can add a read lock to the resource (the lock is degraded); if a thread adds a read lock to a resource, other threads can continue to add a read lock.

The following code shows how to use reentry to perform lock degradation after upgrading cache (exception handling and some codes are omitted for simplicity):

class CachedData {
   Object data;
     //Ensure state visibility
   volatile boolean cacheValid;
   ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

   void processCachedData() {
     rwl.readLock().lock();
     if (!cacheValid) {
        // Read lock must be released before acquiring write lock
        rwl.readLock().unlock();
        rwl.writeLock().lock();
        //Check again if other threads have been preempted  
        if (!cacheValid) {
           //get data
          data = ...
          cacheValid = true;
        }
        // Demote by acquiring read lock before releasing write lock
        rwl.readLock().lock();
        //Release write lock, keep read lock
        rwl.writeLock().unlock();
     }

     use(data);
     rwl.readLock().unlock();
   }
 }

ReentrantReadWriteLock does not inherit ReentrantLock and does not implement the Lock interface, but implements the ReadWriteLock interface, which provides the readLock() method to obtain the read Lock and the writeLock() to obtain the write Lock.

When using some kinds of collections, you can use ReentrantReadWriteLock to improve concurrency. Generally, when the expected collection is large, the reader thread accesses it more times than the writer thread, and the cost of entail operation is higher than the cost of synchronization, it is worth trying. For example, here is a class that uses TreeMap, which is expected to be large and accessible at the same time.

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(); }
    }
 }

Posted by InfinityChiken on Mon, 25 Nov 2019 09:31:28 -0800