ReentrantReadWriteLock Read-Write Lock

Focus on micro-channel public number JavaStorm get the latest articles.
Java Storm

Outline

ReentrantReadWriteLock Lock is another implementation, we already know ReentrantLock is an exclusive lock, at the same time allowing only one thread to access, and ReentrantReadWriteLock allows multiple threads simultaneously read access, but not write and read thread thread, the writer thread and write threads access. With respect to the exclusive lock to improve concurrency. In practice, access to shared data (e.g., cache) a read operation is in most cases much more than a write operation, then ReentrantReadWriteLock is possible to provide better than exclusive lock concurrency and throughput.

Read and write internal lock maintains two locks, one for read and one for write operations. ReadWriteLock all implementations must ensure synchronous memory effect writeLock operation should liaise with the relevant readLock. In other words, success acquire a read lock thread will see all updates before the write lock version did.

ReentrantReadWriteLock supports the following features:

  1. Support fair and equitable access to non-lock mode.
  2. Support reentrant, after reading a thread to acquire a read lock can also get a read lock, but can obtain a write lock; the write thread can acquire a write lock again acquiring both write lock can also get a read lock.
  3. Allow downgrading from the write lock to read lock, its implementation is: to obtain a write lock, and then acquire a read lock, and finally release the write lock. However, upgrading from a read lock to write lock is not possible;
  4. Read lock and write lock both support interruption during lock acquisition;
  5. Condition support. Only write lock provides a Conditon realization; read lock does not support Conditon, readLock () newCondition () throws UnsupportedOperationException..

scenes to be used

Example 1: Use reentrant lock after performing an upgrade cache downgrade

In the cache is valid, supports concurrent read. Cache invalidation, allowing only exclusive write.

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class HibernateCache {

    /* 定义一个Map来模拟缓存 */
    private Map<String, Object> cache = new HashMap<String, Object>();

    /* 创建一个读写锁 */
    private ReadWriteLock rwLock = new ReentrantReadWriteLock();

    /**
     * 模拟Hibernate缓存,优先缓存,若缓存不存在写锁更新
     *
     * @param key
     * @return
     */
    public Object getData(String key) {

        /* 上读锁 */
        rwLock.readLock().lock();
        /* 定义从缓存中读取的对象 */
        Object value = null;

        try {
            /* 从缓存中读取数据 */
            value = cache.get(key);

            if (value == null) {
                /* 如果缓存中没有数据,我们就把读锁关闭,直接上写锁【让一个线程去数据库中取数据】 */
                rwLock.readLock().unlock();
                /* 上写锁 */
                rwLock.writeLock().lock();

                try {
                    /* 上了写锁之后再判断一次【我们只让一个线程去数据库中取值即可,当第二个线程过来的时候,发现value不为空了就去缓存中取值】 */
                    if (value == null) {
                        /* 模拟去数据库中取值 */
                        value = "hello";
                        System.out.println("修改换缓存");
                        cache.put(key, value);
                    }
                } finally {
                    /* 写完之后把写锁关闭 */
                    rwLock.writeLock().unlock();
                }
                /* 缓存中已经有了数据,我们再把已经 关闭的读锁打开 */
                rwLock.readLock().lock();
            }
            return value;

        } finally {
            /* 最后把读锁也关闭 */
            rwLock.readLock().unlock();
        }

    }

    public Map<String, Object> getCache() {
        return cache;
    }

    public void setCache(Map<String, Object> cache) {
        this.cache = cache;
    }
}
复制代码

Example Two: high concurrent read and write shared data

When a shared data can only give you a Xi'an write data mapping, multiple threads can read data. You can choose to read and write locks support concurrent read, exclusive write, improve concurrency.

code show as below:

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWrite {

    private ReadWrite() {
    }

    private static class singleFactory {
        private static final ReadWrite INSTANCE = new ReadWrite();
    }

    public static ReadWrite getInstance() {
        return singleFactory.INSTANCE;
    }

    /* 共享数据,只能一个线程写数据,可以多个线程读数据 */
    private Object data = null;
    /* 创建一个读写锁 */
    ReadWriteLock rwlock = new ReentrantReadWriteLock();

    /**
     * 读数据,可以多个线程同时读, 所以上读锁即可
     */
    public void get() {
        /* 上读锁 */
        rwlock.readLock().lock();

        try {
            System.out.println(Thread.currentThread().getName() + " 准备读数据!");
            /* 休眠 */
            Thread.sleep((long) (Math.random() * 1000));
            System.out.println(Thread.currentThread().getName() + "读出的数据为 :" + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            rwlock.readLock().unlock();
        }

    }

    /**
     * 写数据,多个线程不能同时 写 所以必须上写锁
     *
     * @param data
     */
    public void put(Object data) {

        /* 上写锁 */
        rwlock.writeLock().lock();

        try {
            System.out.println(Thread.currentThread().getName() + " 准备写数据!");
            /* 休眠 */
            Thread.sleep((long) (Math.random() * 1000));
            this.data = data;
            System.out.println(Thread.currentThread().getName() + " 写入的数据: " + data);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rwlock.writeLock().unlock();
        }
    }
}

复制代码

unit test

public class LockTest {
    public static void main(String[] args) {
        ReadWrite readWrite = ReadWrite.getInstance();


        for (int i = 0; i < 8; i++) {
            /* 创建并启动8个读线程 */
            new Thread(() -> readWrite.get()).start();

            /*创建8个写线程*/
            new Thread(() -> readWrite.put(new Random().nextInt(8))).start();
        }
    }


}
复制代码

operation result:

Thread-0读出的数据为 :null
Thread-1 准备写数据!
Thread-1 写入的数据: 6
Thread-3 准备写数据!
Thread-3 写入的数据: 4
Thread-4 准备读数据!
Thread-2 准备读数据!
Thread-2读出的数据为 :4
Thread-4读出的数据为 :4
Thread-5 准备写数据!
Thread-5 写入的数据: 1
Thread-6 准备读数据!
Thread-6读出的数据为 :1
Thread-7 准备写数据!
Thread-7 写入的数据: 6
Thread-8 准备读数据!
Thread-8读出的数据为 :6
Thread-9 准备写数据!
Thread-9 写入的数据: 4
Thread-10 准备读数据!
Thread-10读出的数据为 :4
Thread-11 准备写数据!
Thread-11 写入的数据: 4
Thread-12 准备读数据!
Thread-12读出的数据为 :4
Thread-13 准备写数据!
Thread-13 写入的数据: 6
Thread-14 准备读数据!
Thread-14读出的数据为 :6
Thread-15 准备写数据!
Disconnected from the target VM, address: '127.0.0.1:55431', transport: 'socket'
Thread-15 写入的数据: 0
复制代码

There is a rule here: obtaining a write lock after data must one go from ready to write data to the write data, that is, atomic operations, exclusive thread.

And in the case of a read lock may have multiple threads ready to be read, multiple threads simultaneously read data.


Guess you like

Origin juejin.im/post/5cee32a76fb9a07eb051a401