Read-write locks ReadWriteLock and ReentrantReadWriteLock

Interface dependency graph

write picture description here
Interface dependency diagram of ReentrantReadWriteLock

Overview

The Java Concurrent Programming Package provides an implementation of read-write locks that maintain a pair of related locks, a "read lock" and a "write lock", one for read operations and the other for write operations.

A "read lock" is used for read-only operations, and it is a "shared lock" that can be acquired by multiple threads at the same time.
The "write lock" is used for write operations, it is an "exclusive lock", and the write lock can only be acquired by one thread lock.

The so-called read-write locks are shared locks and exclusive locks for accessing resources. The general reentrancy 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 read locks to resources (lock degradation); if one thread adds read locks to resources, other threads can continue to add read locks.

ReadWriteLock ReadWriteLock is an interface. ReentrantReadWriteLock is its implementation class, ReentrantReadWriteLock includes internal classes ReadLock and WriteLock.

The source code of java.util.concurrent.locks.ReadWriteLock is as follows:

public interface ReadWriteLock {
    //获取一个读锁
    Lock readLock();
    //获取一个写锁
    Lock writeLock();
}

ReentrantReadWriteLock supports the following functions:

1) Support fair and unfair ways of acquiring locks;

2) Support reentrancy. The reader thread can also acquire the read lock after acquiring the read lock; the writer thread can acquire both the write lock and the read lock again after acquiring the write lock;

3) It is also allowed to downgrade from a write lock to a read lock. The implementation method is: first acquire the write lock, then acquire the read lock, and finally release the write lock. However, upgrading from a read lock to a write lock is not allowed;

4) Both read locks and write locks support interrupts during lock acquisition;

5) Condition support. Write-only locks provide a Conditon implementation; read locks do not support Conditon, and readLock().newCondition() throws UnsupportedOperationException.

java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock.newCondition()

public Condition newCondition() {
    throw new UnsupportedOperationException();
}

java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock.newCondition()

public Condition newCondition() {
    return sync.newCondition();
}

use

Example 1: Using reentrancy to perform lock downgrade after upgrading the cache

class CachedData {
   Object data;
     //保证状态可见性
   volatile boolean cacheValid;
   ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

   void processCachedData() {
     rwl.readLock().lock();
     if (!cacheValid) {
        // 在获取写锁前必须释放读锁
        rwl.readLock().unlock();
        rwl.writeLock().lock();
        //再次检查其他线程是否已经抢到  
        if (!cacheValid) {
           //获取数据
          data = ...
          cacheValid = true;
        }
        // 在释放写锁之前通过获取读锁来降级
        rwl.readLock().lock();
        //释放写锁,保持读锁
        rwl.writeLock().unlock();
     }

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

Example 2: Use ReentrantReadWriteLock to improve the concurrency of Collection

ReentrantReadWriteLock can be used to improve concurrency when using certain kinds of Collections. In general, this is worth a try when the Collection is expected to be large, the reader threads access it more than the writer threads, and the overhead of the enter operation is higher than the synchronization overhead. For example, here is a class that uses a TreeMap, which is expected to be large and be accessed simultaneously.

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

Reference documents:
1. https://www.cnblogs.com/zaizhoumo/p/7782941.html
2. https://blog.csdn.net/prestigeding/article/details/53286756
3. https://blog.csdn .net/qq924862077/article/details/70303821

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325452720&siteId=291194637