先看到构造方法
public ReentrantReadWriteLock() {
//无惨构造函数,默认非公平锁
this(false);
}
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
//FairSync和NonfairSync继承Sync
Sync() {
//该属性读锁会用到 ,用来记录各个线程的加读锁的次数
readHolds = new ThreadLocalHoldCounter();
setState(getState()); // ensures visibility of readHolds
}
//重写initialValue,返回一个HoldCounter
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();
}
}
static final class HoldCounter {
//读锁加锁的次数
int count = 0;
//线程id
final long tid = getThreadId(Thread.currentThread());
}
写锁
先看到写锁的加锁过程
public void lock() {
//调用到aqs的acquire方法,acquire方法之前文章已经解析过了
sync.acquire(1);
}
//看到ReentrantReadWriteLock对tryAcquire的实现
protected final boolean tryAcquire(int acquires) {
//获取当前线程
Thread current = Thread.currentThread();
//获取aqs的state
int c = getState();
//计算state的后16位的值,用来表示写锁的state值
//c & 65535 (后16为全部为1,前16位全部为0)
int w = exclusiveCount(c);
//已经有线程上了锁了,可能是写锁,也可能是读锁
if (c != 0) {
if (w == 0 || current != getExclusiveOwnerThread())
//w==0 上的不是写锁 ,被上了读锁,则不让上写锁。
//或者 w=!0 被上了写锁,current != getExclusiveOwnerThread() ,且上写锁的不是自己。
//加锁失败,去排队。
return false;
//w != 0 且 current == getExclusiveOwnerThread() 自己重入上写锁,只有16位表示,不能超过65535
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//重入,增加state值
setState(c + acquires);
//加锁成功
return true;
}
//没有被上锁
//writerShouldBlock判断是否需要去排队
//如果不需要排队 , cas设置state的值
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
//writerShouldBlock返回true , 需要排队 , 则返回false 加锁失败
//cas失败,则说明被其他线程抢到了锁, 则返回false 加锁失败
//排队去。
return false;
//cas设置state的值 成功,将当前持有锁的设置为自己
setExclusiveOwnerThread(current);
//返回true 加锁成功
return true;
}
writerShouldBlock方法
//FairSync公平锁的实现
final boolean writerShouldBlock() {
//该方法之前的文章已经解析过了,判断队列里是否有其他线程在排队
return hasQueuedPredecessors();
}
//NonfairSync非公平锁的实现
final boolean writerShouldBlock() {
//直接返回false
return false;
}
再看到写锁的解锁过程
public void unlock() {
//调用到aqs的release方法,release方法之前文章已经解析过了
sync.release(1);
}
//看到ReentrantReadWriteLock对tryRelease的实现
protected final boolean tryRelease(int releases) {
//持有锁的线程不是当前线程报错
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//state减去releases的值
int nextc = getState() - releases;
//判断state后16位的值,是否为0
boolean free = exclusiveCount(nextc) == 0;
//为0,将当前线程设置为空
if (free)
setExclusiveOwnerThread(null);
//将减去后的值,设置回state
setState(nextc);
//为0返回true,解锁成功
return free;
}
读锁
先看到读锁的加锁过程
public void lock() {
sync.acquireShared(1);
}
public final void acquireShared(int arg) {
//加读锁
if (tryAcquireShared(arg) < 0)
//加读锁失败,要去排队
doAcquireShared(arg);
}
private void doAcquireShared(int arg) {
//addWaiter之前文章以及分析过了
//将当前线程包装为node,然后进入同步等待队列排队,这里传入了一个Node.SHARED参数,赋值node的nextWaiter属性,以此来标识这个node是一个读锁的节点
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
//死循环
for (;;) {
//获取node的前一个节点
final Node p = node.predecessor();
//p如果为头结点
if (p == head) {
//加读锁,读锁的tryAcquireShared只会返回1和-1,1标识加锁成功,-1标识加锁失败
int r = tryAcquireShared(arg);
//加锁成功
if (r >= 0) {
//设置自己为头结点,并唤醒后面的连续的读锁节点
setHeadAndPropagate(node, r);
//将p的next属性清空
p.next = null; // help GC
if (interrupted)
//如果被打断过,这里打断自己,设置打断标识,表示自己曾经被打断过
selfInterrupt();
failed = false;
return;
}
}
//shouldParkAfterFailedAcquire之前文章已经分析过了
//shouldParkAfterFailedAcquire设置前置节点的waitStatus
//parkAndCheckInterrupt进行休眠,醒来后清除打断标识,并返回是否被打断过
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//被打断过,修改interrupted 为true
interrupted = true;
}
} finally {
if (failed)
//cancelAcquire之前的文章已经分析过了
//在同步等待队列中断开被取消的节点
cancelAcquire(node);
}
}
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head;
//设置node为头结点,将node的thread和prev属性置空
setHead(node);
//读锁传进来的propagate 一定大于0 ,后面写Semaphore的时候再来看=0的情况
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
//获取node的下一个节点
Node s = node.next;
//如果下一个节点也是读锁节点
if (s == null || s.isShared())
//唤醒队列中等待的节点,显然队列中所有连续排队的读锁节点都会被唤醒,直到遇到一个写锁节点,则上处 s.isShared()判断不成立。
doReleaseShared();
}
}
//读锁的排队等待的node的nextWaiter 属性为SHARED
//Node类初始化的常量 static final Node SHARED = new Node();
final boolean isShared() {
return nextWaiter == SHARED;
}
tryAcquireShared方法
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
//获取state的值
int c = getState();
//计算state后16位的值是否为0 , 判断持有锁的线程是否为自己
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
//state后16位的值不为0(已经上了写锁),且持有锁的线程不是自己
//返回-1,加锁失败
return -1;
//走到这里
//没有被上写锁
//或者上写锁的是自己
//计算state的前16的值 (c >>> 16 右移16位,抛弃后16位)
int r = sharedCount(c);
//readerShouldBlock判断是否需要去排队
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
//读锁不用排队,次数没有超过65535,且cas设置state成功
//如果r为0,说明没线程在上读锁
if (r == 0) {
//将firstReader 设置为当前线程
firstReader = current;
//firstReaderHoldCount 为 1
firstReaderHoldCount = 1;
//如果r不为0,但是firstReader是当前线程,重入了
} else if (firstReader == current) {
//firstReaderHoldCount++
firstReaderHoldCount++;
} else {
//获取cachedHoldCounter(记录最近一次来拿读锁的线程),多种情况
//1. firstReader为线程1,则线程2上读锁时走到这里,此时cachedHoldCounter为空 ,rh 为空
//2. firstReader为线程1,当线程2再次上读锁时,cachedHoldCounter不为空 ,rh 不为空, rh.tid != getThreadId(current)不成立 ,rh.count == 0也不成立,只运行rh.count++;
//2.1 firstReader为线程1, 线程2释放了全部的读锁(解锁时会扣减count,count为0时,会从readHolds移除),然后线程2再次来加读锁,此时cachedHoldCounter不为空 ,rh 不为空,则走下一个判断rh.count == 0成立;
//3.线程3走到这里时,cachedHoldCounter记录的线程2,cachedHoldCounter不为空 ,rh 不为空,rh.tid != getThreadId(current)成立
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
//1. readHolds.get() 此时HoldCounter 的count为0,cachedHoldCounter 记录的是线程2
//3. readHolds返回一个新的HoldCounter ,cachedHoldCounter此时 记录的是线程3
cachedHoldCounter = rh = readHolds.get();
//2.1 走这里
else if (rh.count == 0)
//将rh设置回readHolds中
readHolds.set(rh);
//读次数加一
rh.count++;
}
//返回1,读锁上锁成功
return 1;
}
//读锁上锁失败,还没完,接着调用fullTryAcquireShared
return fullTryAcquireShared(current);
}
readerShouldBlock方法
//FairSync公平锁的实现
final boolean readerShouldBlock() {
//判断队列是否有线程在排队
return hasQueuedPredecessors();
}
//NonfairSync非公平锁的实现
final boolean readerShouldBlock() {
//当队列中头节点的下一个节点为写锁的等待节点时,返回true,需要将此时请求上读锁的线程阻塞
//防止读操作过多,导致排队的写操作长时间无法进行,导致新来读操作全部脏读
return apparentlyFirstQueuedIsExclusive();
}
final boolean apparentlyFirstQueuedIsExclusive() {
Node h, s;
//有头结点 头结点赋值给h
//头结点有下个节点(正在排队等待的线程) 下个节点赋值给s
//s的是否为 共享节点(读锁的节点)
//节点的thread属性不为空(还没有被唤醒,并抢锁成功成为头结点)
return (h = head) != null &&
(s = h.next) != null &&
!s.isShared() &&
s.thread != null;
}
fullTryAcquireShared方法
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
//死循环
for (;;) {
int c = getState();
//判断是否被上了写锁
if (exclusiveCount(c) != 0) {
//被上了写锁
//判断上写锁的线程是不是自己
if (getExclusiveOwnerThread() != current)
//被其他线程上了写锁,返回-1,加锁失败
return -1;
}
//没有被上写锁,判断读锁是否要被阻塞
else if (readerShouldBlock()) {
//读锁需要阻塞 此时不一定需要阻塞,可能是读锁重入
//第一个上读锁的是自己
if (firstReader == current) {
}
//第一个上读锁的不是自己
else {
if (rh == null) {
//获取cachedHoldCounter
rh = cachedHoldCounter;
//rh == null ,自己是第二个来上读锁的
//rh != null 且 rh.tid != getThreadId(current) 最近一次上读锁的不是自己
if (rh == null || rh.tid != getThreadId(current)) {
//获取自己的HoldCounter
rh = readHolds.get();
//如果是0 ,说明自己当前没有上读锁
if (rh.count == 0)
//移除自己的HoldCounter
readHolds.remove();
}
}
//自己当前没有上过读锁的话
if (rh.count == 0)
//返回-1,加锁失败
return -1;
}
}
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//走到这里,说明当前当前没有写锁,读锁也不用排队
//cas 修改state
if (compareAndSetState(c, c + SHARED_UNIT)) {
//cas修改成功
//下面代码和tryAcquireShared中加读锁代码一样的了,就不赘述了
if (sharedCount(c) == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
//读锁加锁成功,修改cachedHoldCounter为自己
cachedHoldCounter = rh; // cache for release
}
//返回1 标识加锁成功
return 1;
}
//cas修改失败,state被其他线程修改了,接着下一次循环。
}
}
看到读锁的解锁流程
public void unlock() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
//如果当前没有线程在加锁,唤醒队列中等待的节点
doReleaseShared();
return true;
}
return false;
}
releaseShared方法
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
//firstReader 是否为自己
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
//如果firstReaderHoldCount 为1 ,则该线程的读锁解锁完毕,将firstReader置空
if (firstReaderHoldCount == 1)
firstReader = null;
//重入次数减一
else
firstReaderHoldCount--;
}
//第一个加读锁的不是自己
else {
//获取最近一次加读锁的HoldCounter
HoldCounter rh = cachedHoldCounter;
//如果rh为空
//或者rh不为空,但是rh.tid != getThreadId(current) 最近一次加读锁的线程不是自己
if (rh == null || rh.tid != getThreadId(current))
//获取到自己的HoldCounter
rh = readHolds.get();
//获取读锁加锁的次数
int count = rh.count;
if (count <= 1) {
//从readHolds移除自己的HoldCounter
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
//将读锁加锁次数减一
--rh.count;
}
//死循环
for (;;) {
int c = getState();
//减去65535 , 读锁用的是stated的前16位
int nextc = c - SHARED_UNIT;
//cas设置stated的值 设置不成功说明还有其他线程在加解锁,则接着循环,直至设置成功
if (compareAndSetState(c, nextc))
//返回解锁后的state是否为0,也就是当前是否还有锁(读锁或者写锁)
return nextc == 0;
}
}
doReleaseShared方法
private void doReleaseShared() {
//死循环
for (;;) {
//获取头节点
Node h = head;
//如果头结点不为空 且 头结点不等于尾节点
if (h != null && h != tail) {
int ws = h.waitStatus;
//如果节点waitStatus为SIGNAL,则需要唤醒后继节点
if (ws == Node.SIGNAL) {
//cas将节点的waitStatus改为0
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
//cas失败,则执行一下次循环
continue; // loop to recheck cases
//unparkSuccessor之前的文章以及分析过了
//cas成功,唤醒h的后继节点 ,
unparkSuccessor(h);
}
//如果头结点的waitstatus为0
//则 cas 将头结点修改为PROPAGATE,如果cas成功,其实没有什么作用,然后执行后续代码,很可能就跳出循环了。
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
//cas失败反而是有用的,cas失败很可能是队列中进入了节点把头结点的waitstatus修改成了-1
//此时执行一下次循环重新获取头结点的waitStatus,可以唤醒刚进来的节点
continue; // loop on failed CAS
}
//跳出循环,如果头结点没有发生变化
//发生变化,再次循环一次
if (h == head) // loop if head changed
break;
}
}
到此,ReentrantReadWriteLock源码也就解析完毕,这里许多aqs的代码,在之前ReentrantLock源码解析文章里面讲过,这里就没赘述了。