Read-write lock

ReentrantReadWriteLock

When the read operation is much higher than the write operation, use read/write locks to allow read-read concurrency and improve performance. Similar to select in a database… from… Lock in Share Mode provides a read() method inside a data container class that protects data with a read lock and a write() method that protects data

public class TestReadWriteLock {
    public static void main(String[] args) {

        DataContainer dataContainer = new DataContainer();
        new Thread(() -> {
            dataContainer.read();
        }, "read").start();

        new Thread(() -> {
            dataContainer.write();
        }, "write").start(); }}@Slf4j
class DataContainer {
    private Object data;
    private ReentrantReadWriteLock rw = new ReentrantReadWriteLock();
    private ReentrantReadWriteLock.ReadLock r = rw.readLock();
    private ReentrantReadWriteLock.WriteLock w = rw.writeLock();

    public Object read(a) {
        log.debug("Get read lock...");
        r.lock();
        try {
            log.debug("read");
            sleep(1000);
            return data;
        } finally {
            log.debug("Release read lock..."); r.unlock(); }}public void write(a) {
        log.debug("Get write lock");
        w.lock();
        try {
            log.debug("write");
        } finally {
            log.debug("Release write lock"); w.unlock(); }}}Copy the code

Output:

00:29:24. 932 / read the DEBUG com. Tyroxyz. Multithread. Multi. The DataContainer – get read lock… 00:29:24. 932 [write] the DEBUG com. Tyroxyz. Multithread. Multi. DataContainer – access to write lock 00:29:24. 945 (read) the DEBUG Com. Tyroxyz. Multithread. Multi. The DataContainer – read 00:29:25. 946 / read the DEBUG com. Tyroxyz. Multithread. Multi. The DataContainer – Release read locks… 00:29:25. 946 [write] the DEBUG com. Tyroxyz. Multithread. Multi. The DataContainer – write 00:29:25, 946 [write] the DEBUG Com. Tyroxyz. Multithread. Multi. The DataContainer – write lock release

Matters needing attention

  • Read locks do not support condition variables
  • Reentry upgrade is not supported: Obtaining a write lock while holding a read lock will cause a permanent wait for obtaining the write lock
r.lock();
try {
    w.lock();
    try {
        / /...
    } finally{ w.unlock(); }}finally {
    r.unlock();
}
Copy the code
  • Reentrant degradation support: obtain read locks while holding write locks
class CachedData {
    Object data;
    // Whether the data is valid. If it is invalid, you need to recalculate data
    volatile boolean cacheValid;
    final ReentrantReadWriteLock rw1 = new ReentrantReadWriteLock();
    void processCachedDate(a) {
        rw1.readLock().lock();
        if(! cacheValid) {// The read lock must be released before the write lock is acquired
            rw1.readLock().unlock();
            rw1.writeLock().lock();
            try {
                // Determine whether another thread has acquired the write lock and updated the cache to avoid repeated updates
                if(! cacheValid) { data = ... ; cacheValid =true;                           
                }
                // Downgrade to a read lock and release the write lock so that other threads can read the cache
                rw1.readLock().lock();
            } finally{ rw1.writeLock().unlock(); }}// Release read lock when you run out of data
        try {
            use(data);
        } finally{ rw1.readLock().unlock(); }}}Copy the code