Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

1. Introduction to ReadWriteLock

ReadWriteLock

In Java. Util. Concurrent. The locks in the package defines the ReadWriteLock interface, the interface defines readLock () returns to read locks, define writeLock write lock () method returns. One for read (==readLock readLock ==) and one for write (==writeLock writeLock ==). The implementation class for this interface is ReentrantReadWriteLock(reentrant read/write lock).

A thread must hold a read lock before reading shared data. The read lock can be held by multiple threads at the same time, that is, it is shared. A thread must hold a write lock before modifying the shared data. The write lock is exclusive (exclusive). When one thread holds a write lock, other threads cannot obtain the corresponding lock.

A read lock is only shared between reader threads. When any thread holds the read lock, other threads cannot obtain the write lock. This ensures that no other thread updates the data during data reading.

Read/write locks allow:

  • Read sharing: Read – read operations can coexist

  • Read/write mutually exclusive: Read/write operations cannot coexist

  • Write mutually exclusive: Write – write operations cannot coexist

For conditions exclusive role
Read lock The write lock is not held by any thread Shared to the reader thread and exclusive to the writer thread Multiple reader threads can read the shared data at the same time, ensuring that no other threads modify the shared data
Write lock The write lock is not held by any other thread, and the corresponding read lock is not held by any other thread Either the reader thread or the writer thread is exclusive Ensure that the writer thread modifies the shared data exclusively

2. ReadWriteLock

Simulates writing and reading of cached data

No read/write lock

package com.cheng.rw;

import java.util.HashMap;
import java.util.Map;

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

        MyCache myCache = new MyCache();
        / / write operations
        for (int i = 0; i < 5; i++) {
            final int temp = i;
            new Thread(()->{
                myCache.set(temp+"",temp+"");
            },String.valueOf(i)).start();
        }
        / / read operation
        for (int i = 0; i < 5; i++) {
            final int temp = i;
            new Thread(()->{
                myCache.get(temp+""); },String.valueOf(i)).start(); }}}class MyCache{

    private volatile Map<String,Object> map = new HashMap<>();

    / / write operations
    public void set(String key,Object value){
        System.out.println(Thread.currentThread().getName()+"Written in"+key);
        map.put(key,value);
        System.out.println(Thread.currentThread().getName()+Write operation completed);

    }
    / / read operation
    public void get(String key){
        System.out.println(Thread.currentThread().getName()+"Read"+key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName()+"Read operation completed"); }}Copy the code

Run to view the result:

Without a read/write lock, the current thread is interrupted by another thread while writing.

Add read/write lock

package com.cheng.rw;

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

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

        MyCacheLock myCache = new MyCacheLock();
        / / write operations
        for (int i = 0; i < 5; i++) {
            final int temp = i;
            new Thread(()->{
                myCache.set(temp+"",temp+"");
            },String.valueOf(i)).start();
        }
        / / read operation
        for (int i = 0; i < 5; i++) {
            final int temp = i;
            new Thread(()->{
                myCache.get(temp+""); },String.valueOf(i)).start(); }}}class MyCacheLock{

    private volatile Map<String,Object> map = new HashMap<>();
    private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();// Define read/write locks
    / / write operations
    public void set(String key,Object value){
        readWriteLock.writeLock().lock();// Add write lock
        try {
            System.out.println(Thread.currentThread().getName()+"Written in"+key);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+Write operation completed);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();// Release the write lock}}/ / read operation
    public void get(String key){
        readWriteLock.readLock().lock();// Add read lock
        try {
            System.out.println(Thread.currentThread().getName()+"Read"+key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName()+"Read operation completed");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();// Release the read lock}}}Copy the code

Run to view the result:

A write operation can be performed by only one thread at a time, and a read operation can be performed by multiple threads at the same time.

3. Advantages of read-write locks over other locks

Synchronized internal lock and ReentrantLock are exclusive locks. Only one thread is allowed to execute a synchronized code block at a time. This ensures thread security, but the execution efficiency is low.

The ReentrantReadWriteLock read-write lock is an improved exclusive lock, also known as a shared/exclusive lock. Allowing multiple threads to read shared data at the same time improves the efficiency of the program, but only one thread is allowed to update the shared data at a time.

ReentrantReadWriteLock more granular control of reading and writing to resources.