ReentrantReadWriteLock原理分析

ReentrantReadWriteLock顾名思义是可重入的读写锁,允许多个读线程获得ReadLock,但只允许一个写线程获得WriteLock。

注意:本文内容是基于jdk1.8.0_40的,不同jdk版本可能某些实现会有所修改。


原理介绍

1. ReentrantReadWriteLock类图:


ReentrantReadWriteLock原理分析_第1张图片


ReentrantReadWriteLock原理分析_第2张图片



2. ReentrantReadWriteLock内部定义了static abstrat Sync类,它继承自AQS。


3. ReentrantReadWriteLock提供的ReadLock是共享的,而WriteLock是独占的。于是Sync类同时实现了AQS中独占和共享模式的抽象方法(tryAcquire/tryAcquireShared等),用同一个等待队列来维护读/写排队线程,而用一个32位int state标示和记录读/写锁重入次数--这里要实现读锁和写锁,只有一个状态怎么办?Doug Lea是这么做的,它把状态的高16位用作读锁,记录所有读锁重入次数之和,低16位用作写锁,记录写锁重入次数。所以无论是读锁还是写锁最多只能被持有65535次。


4. FairSync和NonfairSync继承自Sync类,实现了公平/非公平策略。


ReentrantReadWriteLock特性


  • 公平性

    • 非公平锁(默认),为了防止写线程饿死,规则是:当等待队列头部结点是独占模式(即要获取写锁的线程)时,只有获取独占锁线程可以抢占,而试图获取共享锁的线程必须进入队列阻塞;当队列头部结点是共享模式(即要获取读锁的线程)时,试图获取独占和共享锁的线程都可以抢占。

    • 公平锁,利用AQS的等待队列,线程按照FIFO的顺序获取锁,因此不存在写线程一直等待的问题。

  • 重入性
    • 读写锁均是可重入的,读/写锁重入次数保存在了32位int state的高/低16位中。而单个读线程的重入次数,则记录在ThreadLocalHoldCounter类型的readHolds里。

  • 锁降级

    • 写线程获取写入锁后可以获取读取锁,然后释放写入锁,这样就从写入锁变成了读取锁,从而实现锁降级。

  • 锁获取中断

    • 读取锁和写入锁都支持获取锁期间被中断。

  • 条件变量

    • 写锁提供了条件变量(Condition)的支持,这个和独占锁ReentrantLock一致,但是读锁却不允许,调用readLock().newCondition()会抛出UnsupportedOperationException异常。


相关文章链接

并发编程实践六:ReentrantReadWriteLock (原理和源码解析)

Java并发-ReentrantReadWriteLock源码分析 

你可能感兴趣的:(java多线程,java)