【读写锁】java ReentrantReadWriteLock学习

ReadWriteLock 是什么

  • 首先明确一下,不是说 ReentrantLock 不好,只是 ReentrantLock 某些时候有局限。
    • 如果使用 ReentrantLock,可能本身是为了防止线程 A 在写数据、线程 B 在读数据造成的数据不一致,
  • 但这样,如果线程 C 在读数据、线程 D 也在读数据,读数据是不会改变数据的,没有必要加锁,但是还是加锁了,降低了程序的性能。因为这个,才诞生了读写锁 ReadWriteLock。
  • ReadWriteLock 是一个读写锁接口,读写锁是用来提升并发程序性能的锁分离技术,
  • ReentrantReadWriteLock 是 ReadWriteLock 接口的一个具体实现,实现了读写的分离,读锁是共享的,写锁是独占的,读和读之间不会互斥,读和写、写和读、写和写之间才会互斥,提升了读写的性能。

读写锁的意义

ReadWriteLock 接口的一个具体实现,实现了读写的分离,读锁是共享的,写锁是独占的,读和读之间不会互斥,读和写、写和读、写和写之间才会互斥,提升了读写的性能。

读写锁特性: 3`

(1)公平选择性:支持非公平(默认)和公平的锁获取方式,吞吐量还是非公平优于公平。
(2)重进入:读锁和写锁都支持线程重进入。
(3)锁降级:遵循获取写锁、获取读锁再释放写锁的次序,写锁能够降级成为读锁。

使用

1、基本使用案例

package lockTest.reentrantReadWriteLock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @Author: WalkerShen
 * @DATE: 2022/3/22
 * @Description: 读写锁
 **/
public class ReadWriteLockTest {
    /**
     * public ReentrantReadWriteLock(boolean fair)
     * ReentrantReadWriteLock也可以实现公平锁和非公平锁
     */
    private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    private final static Lock readLock = readWriteLock.readLock();
    private final static Lock writeLock = readWriteLock.writeLock();
    private final static List<Integer> dataList = new ArrayList<>();

    public static void main(String[] args) {
        new Thread(() -> write()).start();
        new Thread(() -> write()).start();
        new Thread(() -> read()).start();
        new Thread(() -> read()).start();
    }


    /**
     * 读方法
     */
    public static void read() {
        readLock.lock();
        for (Integer data : dataList) {
            System.out.println(Thread.currentThread().getName() + "读取数据:" + data);
        }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            readLock.unlock();
        }


    }

    /**
     * 写方法
     */
    public static void write() {
        writeLock.lock();
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "写数据:" + i);
            dataList.add(i);
        }
        writeLock.unlock();

    }

}

结果:

Thread-0写数据:0
Thread-0写数据:1
Thread-0写数据:2
Thread-0写数据:3
Thread-0写数据:4
Thread-1写数据:0
Thread-1写数据:1
Thread-1写数据:2
Thread-1写数据:3
Thread-1写数据:4
Thread-2读取数据:0
Thread-2读取数据:1
Thread-2读取数据:2
Thread-3读取数据:0
Thread-2读取数据:3
Thread-3读取数据:1
Thread-2读取数据:4
Thread-3读取数据:2
Thread-2读取数据:0
Thread-3读取数据:3
Thread-2读取数据:1
Thread-3读取数据:4
Thread-2读取数据:2
Thread-3读取数据:0
Thread-2读取数据:3
Thread-3读取数据:1
Thread-2读取数据:4
Thread-3读取数据:2
Thread-3读取数据:3
Thread-3读取数据:4

从结果中可以发现,写操作的时候只有Thread-0执行完之后才到Thread-1,
而读操作的时候,Thread-2和Thread-3是交替进行的

2、锁升级

在线程中,写锁的级别是大于读锁的,意思是如果不释放读锁,去获取写锁,是获取不到的,会导致线程阻塞
但是如果持有写锁,去获取读锁,是可以获取到的
意思就是说,读锁到写锁,是需要释放后才可以升级的

package lockTest.reentrantReadWriteLock;

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

/**
 * @Author: WalkerShen
 * @DATE: 2022/3/22
 * @Description: 读写锁结合
 **/
public class ReadWriteCombineTest {

    private static ReentrantReadWriteLock readWriteLock=new ReentrantReadWriteLock();
    /**
     * public static class ReadLock implements Lock, java.io.Serializable
     * 因为ReadLock和WriteLock都是静态内部类,所以需要添加static修饰
     */
    private static Lock readLock=readWriteLock.readLock();
    private static Lock writeLock=readWriteLock.writeLock();
    private static String data=null;

    public static void main(String[] args) {
//        new Thread(()->notReleaseReadLock()).start();

        new Thread(()->releaseReadLock()).start();
    }

    /**
     * 读写结合
     * 在写锁操作的时候,没有释放读锁
     * 这个时候就会阻塞
     */
    public static void notReleaseReadLock(){
        readLock.lock();
        if(data==null){
            writeLock.lock();
            data="aaaa";
            System.out.println(data);
            writeLock.unlock();
        }
        readLock.unlock();
    }


    /**
     * 读写结合
     * 在获取写锁之前先释放掉读锁
     * 输出结果:aaaa
     */
    public static void releaseReadLock(){
        readLock.lock();
        if(data==null){
            readLock.unlock();
            writeLock.lock();
            data="aaaa";
            System.out.println(data);
            writeLock.unlock();
        }
    }


}

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容