An overview of the

ReentrantReadWriteLock is another implementation of Lock. We already know that ReentrantLock is an exclusive Lock that allows only one thread to access it at a time. ReentrantReadWriteLock allows multiple reader threads to access it simultaneously. However, the writer thread and the reader thread, and the writer thread and the writer thread are not allowed to access simultaneously. Improved concurrency over exclusive locking. In practice, access to shared data (such as caches) is mostly read rather than write, so ReentrantReadWriteLock provides better concurrency and throughput than exclusive locks.

Read/write locks maintain two internal locks, one for read operations and one for write operations. All ReadWriteLock implementations must ensure that the memory synchronization effect of writeLock operations also remains associated with the associated readLock. That is, the thread that successfully acquired the read lock will see all updates made to the version before the lock was written.

ReentrantReadWriteLock supports the following functions:

  1. Support fair and unfair lock acquisition methods.
  2. Reentrant is supported. The read thread can obtain the read lock after acquiring the read lock, but cannot obtain the write lock. After acquiring the write lock, the writer thread can acquire the write lock again and also acquire the read lock.
  3. It is possible to downgrade from a write lock to a read lock by first acquiring the write lock, then acquiring the read lock, and finally releasing the write lock. However, upgrading from a read lock to a write lock is not possible;
  4. Both read and write locks support breaking during lock acquisition;
  5. Support Condition. Write-only locks provide a Conditon implementation; Read the lock does not support Conditon, readLock (.) newCondition will throw an UnsupportedOperationException ().

Usage scenarios

Example 1: Reentrant lock degradation after upgrade cache

Concurrent reads are supported when the cache is valid. Cache invalid, only exclusive write allowed.

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

public class HibernateCache {

    /* Define a Map to simulate caching */
    private Map<String, Object> cache = new HashMap<String, Object>();

    /* Create a read-write lock */
    private ReadWriteLock rwLock = new ReentrantReadWriteLock();

    /** * Emulated Hibernate cache, priority cache, if cache does not have write lock update **@param key
     * @return* /
    public Object getData(String key) {

        /* Read lock */
        rwLock.readLock().lock();
        /* Defines the object to read from the cache */
        Object value = null;

        try {
            /* Read data from the cache */
            value = cache.get(key);

            if (value == null) {
                /* If there is no data in the cache, we close the read lock and open the write lock */
                rwLock.readLock().unlock();
                /* write lock */
                rwLock.writeLock().lock();

                try {
                    Mysql > select * from database */; mysql > select * from database */
                    if (value == null) {
                        /* Simulate the database to value */
                        value = "hello";
                        System.out.println("Change cache"); cache.put(key, value); }}finally {
                    /* Close the write lock */
                    rwLock.writeLock().unlock();
                }
                /* Open the read lock */
                rwLock.readLock().lock();
            }
            return value;

        } finally {
            /* Close the read lock */rwLock.readLock().unlock(); }}public Map<String, Object> getCache(a) {
        return cache;
    }

    public void setCache(Map<String, Object> cache) {
        this.cache = cache; }}Copy the code

Example 2: Highly concurrent read and write shared data

When a piece of shared data can only be written to you by one Xi ‘an mapping, multiple threads can read the data. You can choose read/write lock, support concurrent read, exclusive write, improve concurrency.

The code is as follows:

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

public class ReadWrite {

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

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

    /* Share data, only one thread can write data, multiple threads can read data */
    private Object data = null;
    /* Create a read-write lock */
    ReadWriteLock rwlock = new ReentrantReadWriteLock();

    /** ** Data can be read by multiple threads at the same time, so the read lock can be */
    public void get(a) {
        /* Read lock */
        rwlock.readLock().lock();

        try {
            System.out.println(Thread.currentThread().getName() + "Ready to read the data!");
            / * dormancy * /
            Thread.sleep((long) (Math.random() * 1000));
            System.out.println(Thread.currentThread().getName() + "The data read is :" + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{ rwlock.readLock().unlock(); }}/** * write data, multiple threads can not write at the same time, so must write lock **@param data
     */
    public void put(Object data) {

        /* write lock */
        rwlock.writeLock().lock();

        try {
            System.out.println(Thread.currentThread().getName() + "Ready to write data!");
            / * dormancy * /
            Thread.sleep((long) (Math.random() * 1000));
            this.data = data;
            System.out.println(Thread.currentThread().getName() + "Data written:" + data);

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

Unit testing

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


        for (int i = 0; i < 8; i++) {
            /* Create and start 8 reader threads */
            new Thread(() -> readWrite.get()).start();

            /* Create 8 writer threads */
            new Thread(() -> readWrite.put(new Random().nextInt(8))).start(); }}}Copy the code

Running results:

Thread0The data read is:null
Thread- 1Ready to write data! Thread- 1Data written:6
Thread- 3Ready to write data! Thread- 3Data written:4
Thread4 -Ready to read data! Thread2 -Ready to read data! Thread2 -The data read is:4
Thread4 -The data read is:4
Thread- 5Ready to write data! Thread- 5Data written:1
Thread- 6Ready to read data! Thread- 6The data read is:1
Thread7 -Ready to write data! Thread7 -Data written:6
Thread- 8 -Ready to read data! Thread- 8 -The data read is:6
Thread9 -Ready to write data! Thread9 -Data written:4
Thread- 10Ready to read data! Thread- 10The data read is:4
Thread- 11Ready to write data! Thread- 11Data written:4
Thread- 12Ready to read data! Thread- 12The data read is:4
Thread- 13Ready to write data! Thread- 13Data written:6
Thread- 14Ready to read data! Thread- 14The data read is:6
Thread- 15Ready to write data! Disconnectedfrom the target VM, address: '127.0.0.1:55431'.transport: 'socket'
Thread- 15Data written:0
Copy the code

There is a rule here: after acquiring a write lock, data must be written from the ready to write data, that is, atomic operation, thread exclusive.

In the case of read lock, there can be multiple threads ready to read, and multiple threads simultaneously read data.

Follow the wechat official account JavaStorm for the latest articles.

JavaStorm