高并发编程之ReentrantReadWriteLock工具类讲解

一、ReentrantReadWriteLock介绍

①、ReentrantReadWriteLock是Lock的另一种实现方式,我们已经知道了ReentrantLock是一个排他锁,同一时间只允许一个线程访问,而ReentrantReadWriteLock允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。相对于排他锁,提高了并发性。在实际应用中,大部分情况下对共享数据(如缓存)的访问都是读操作远多于写操作,这时ReentrantReadWriteLock能够提供比排他锁更好的并发性和吞吐量。

②、读写锁内部维护了两个锁,一个用于读操作,一个用于写操作。所有 ReadWriteLock实现都必须保证 writeLock操作的内存同步效果也要保持与相关 readLock的联系。也就是说,成功获取读锁的线程会看到写入锁之前版本所做的所有更新。

二、ReentrantReadWriteLock支持以下功能:

①、支持公平和非公平的获取锁的方式;
②、支持可重入。读线程在获取了读锁后还可以获取读锁;写线程在获取了写锁之后既可以再次获取写锁又可以获取读锁;
③、还允许从写入锁降级为读取锁,其实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。但是,从读取锁升级到写入锁是不允许的;
④、读取锁和写入锁都支持锁获取期间的中断;

三、Java代码示例

package chapter3.readwritelock;

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

/**
 * @author czd
 */
public class ReadWriteLockTest {
    /**
     * data:模拟数据库
     */
    private static  List data = new ArrayList<>();

    private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    private static Lock readLock = readWriteLock.readLock();

    private static Lock writeLock = readWriteLock.writeLock();

    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                write();
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                read();
            }
        }.start();


    }

    /**
     * 进行写操作
     */
    public static void write(){
        try {
            writeLock.lock();
            System.out.println(Thread.currentThread().getName()+"线程开始写数据!");
            data.add(System.currentTimeMillis());
            TimeUnit.SECONDS.sleep(2);
            System.out.println("写入数据成功!");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            writeLock.unlock();
        }
    }

    /**
     * 进行读操作
     */
    public static void read(){
        try {
            readLock.lock();
            System.out.println(Thread.currentThread().getName()+"线程开始读数据!");
            for(Long L :data){
                System.out.println("数据:" + L);
            }
            TimeUnit.SECONDS.sleep(2);
            System.out.println("读取数据完成!");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            readLock.unlock();
        }
    }
}

输出结果
高并发编程之ReentrantReadWriteLock工具类讲解_第1张图片

四、总结
①、读写锁是一种特殊的自旋锁,它把对共享资源对访问者划分成了读者和写者,读者只对共享资源进行访问,写者则是对共享资源进行写操作。读写锁在ReentrantLock上进行了拓展使得该锁更适合读操作远远大于写操作对场景。一个读写锁同时只能存在一个写锁但是可以存在多个读锁,但不能同时存在写锁和读锁。

②、如果读写锁当前没有读者,也没有写者,那么写者可以立刻获的读写锁,否则必须自旋,直到没有任何的写锁或者读锁存在。如果读写锁没有写锁,那么读锁可以立马获取,否则必须等待写锁释放。(但是有一个例外,就是读写锁中的锁降级操作,当同一个线程获取写锁后,在写锁没有释放的情况下可以获取读锁再释放读锁这就是锁降级的一个过程)

你可能感兴趣的:(并发)