#yyds干货盘点# JUC锁: ReentrantReadWriteLock详解
Posted 灰太狼_cxh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#yyds干货盘点# JUC锁: ReentrantReadWriteLock详解相关的知识,希望对你有一定的参考价值。
JUC锁: ReentrantReadWriteLock详解
ReentrantReadWriteLock数据结构
ReentrantReadWriteLock底层是基于ReentrantLock和AbstractQueuedSynchronizer来实现的,所以,ReentrantReadWriteLock的数据结构也依托于AQS的数据结构。
ReentrantReadWriteLock源码分析
类的继承关系
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable
ReentrantReadWriteLock实现了ReadWriteLock接口,ReadWriteLock接口定义了获取读锁和写锁的规范,具体需要实现类去实现;同时其还实现了Serializable接口,表示可以进行序列化,在源代码中可以看到ReentrantReadWriteLock实现了自己的序列化逻辑。
内部类 - Sync类
类的继承关系
abstract static class Sync extends AbstractQueuedSynchronizer
说明: Sync抽象类继承自AQS抽象类,Sync类提供了对ReentrantReadWriteLock的支持。
类的内部类
Sync类内部存在两个内部类,分别为HoldCounter和ThreadLocalHoldCounter,其中HoldCounter主要与读锁配套使用,其中,HoldCounter源码如下。
// 计数器
static final class HoldCounter
// 计数
int count = 0;
// Use id, not reference, to avoid garbage retention
// 获取当前线程的TID属性的值
final long tid = getThreadId(Thread.currentThread());
说明: HoldCounter主要有两个属性,count和tid,其中count表示某个读线程重入的次数,tid表示该线程的tid字段的值,该字段可以用来唯一标识一个线程。ThreadLocalHoldCounter的源码如下
// 本地线程计数器
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter>
// 重写初始化方法,在没有进行set的情况下,获取的都是该HoldCounter值
public HoldCounter initialValue()
return new HoldCounter();
说明: ThreadLocalHoldCounter重写了ThreadLocal的initialValue方法,ThreadLocal类可以将线程与对象相关联。在没有进行set的情况下,get到的均是initialValue方法里面生成的那个HolderCounter对象。
类的属性
abstract static class Sync extends AbstractQueuedSynchronizer
// 版本序列号
private static final long serialVersionUID = 6317671515068378041L;
// 高16位为读锁,低16位为写锁
static final int SHARED_SHIFT = 16;
// 读锁单位
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
// 读锁最大数量
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
// 写锁最大数量
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
// 本地线程计数器
private transient ThreadLocalHoldCounter readHolds;
// 缓存的计数器
private transient HoldCounter cachedHoldCounter;
// 第一个读线程
private transient Thread firstReader = null;
// 第一个读线程的计数
private transient int firstReaderHoldCount;
说明: 该属性中包括了读锁、写锁线程的最大量。本地线程计数器等。
类的构造函数
// 构造函数
Sync()
// 本地线程计数器
readHolds = new ThreadLocalHoldCounter();
// 设置AQS的状态
setState(getState()); // ensures visibility of readHolds
说明: 在Sync的构造函数中设置了本地线程计数器和AQS的状态state。
内部类 - Sync核心函数分析
对ReentrantReadWriteLock对象的操作绝大多数都转发至Sync对象进行处理。下面对Sync类中的重点函数进行分析
sharedCount函数
表示占有读锁的线程数量,源码如下
static int sharedCount(int c) return c >>> SHARED_SHIFT;
说明: 直接将state右移16位,就可以得到读锁的线程数量,因为state的高16位表示读锁,对应的低十六位表示写锁数量。
exclusiveCount函数
表示占有写锁的线程数量,源码如下
static int exclusiveCount(int c) return c & EXCLUSIVE_MASK;
说明: 直接将状态state和(2^16 - 1)做与运算,其等效于将state模上2^16。写锁数量由state的低十六位表示。
tryRelease函数
/*
* Note that tryRelease and tryAcquire can be called by
* Conditions. So it is possible that their arguments contain
* both read and write holds that are all released during a
* condition wait and re-established in tryAcquire.
*/
protected final boolean tryRelease(int releases)
// 判断是否伪独占线程
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
// 计算释放资源后的写锁的数量
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0; // 是否释放成功
if (free)
setExclusiveOwnerThread(null); // 设置独占线程为空
setState(nextc); // 设置状态
return free;
说明: 此函数用于释放写锁资源,首先会判断该线程是否为独占线程,若不为独占线程,则抛出异常,否则,计算释放资源后的写锁的数量,若为0,表示成功释放,资源不将被占用,否则,表示资源还被占用。
以上是关于#yyds干货盘点# JUC锁: ReentrantReadWriteLock详解的主要内容,如果未能解决你的问题,请参考以下文章
#yyds干货盘点# JUC锁: LockSupport详解