误区:
读写锁公平读锁抢占的时候,是去判断,队列中的第一个是不是写锁,如果是,那么就写入。
公平不公平其实体现在是否要直接抢占,如果前面有写锁,而且被感知,无论公平与否,都会阻塞读锁。
获取写锁后,可以降级为读锁。参照
https://www.jianshu.com/p/cd485e16456e
protected final int11 tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
// exclusiveCount(c) != 0 ---》 用 state & 65535 得到低 16 位的值。如果不是0,说明写锁别持有了。
// getExclusiveOwnerThread() != current----> 不是当前线程
// 如果写锁被霸占了,且持有线程不是当前线程,返回 false,加入队列。获取写锁失败。
// 反之,如果持有写锁的是当前线程,就可以继续获取读锁了。
if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current)
// 获取锁失败
return -1;
// 如果写锁没有被霸占,则将高16位移到低16位。
int r = sharedCount(c);// c >>> 16
// !readerShouldBlock() 和写锁的逻辑一样(根据公平与否策略和队列是否含有等待节点)
// 不能大于 65535,且 CAS 修改成功
if (!readerShouldBlock() && r < 65535 && compareAndSetState(c, c + 65536)) {
// 如果读锁是空闲的, 获取锁成功。
if (r == 0) {
// 将当前线程设置为第一个读锁线程
firstReader = current;
// 计数器为1
firstReaderHoldCount = 1;
}// 如果读锁不是空闲的,且第一个读线程是当前线程。获取锁成功。
else if (firstReader == current) {//
// 将计数器加一
firstReaderHoldCount++;
} else {// 如果不是第一个线程,获取锁成功。
// cachedHoldCounter 代表的是最后一个获取读锁的线程的计数器。
HoldCounter rh = cachedHoldCounter;
// 如果最后一个线程计数器是 null 或者不是当前线程,那么就新建一个 HoldCounter 对象
if (rh == null || rh.tid != getThreadId(current))
// 给当前线程新建一个 HoldCounter
cachedHoldCounter = rh = readHolds.get();
// 如果不是 null,且 count 是 0,就将上个线程的 HoldCounter 覆盖本地的。
else if (rh.count == 0)
readHolds.set(rh);
// 对 count 加一
rh.count++;
}
return 1;
}
// 死循环获取读锁。包含锁降级策略。
return fullTryAcquireShared(current);
}
final int fullTryAcquireShared(Thread current) {
/*
* 这段代码与tryAcquireShared中的代码有部分重复,但整体更简单。
*/
HoldCounter rh = null;
// 死循环
for (;;) {
int c = getState();
// 如果存在写锁
if (exclusiveCount(c) != 0) {
// 并且不是当前线程,获取锁失败,反之,如果持有写锁的是当前线程,那么就会进入下面的逻辑。
// 反之,如果存在写锁,但持有写锁的是当前线程。那么就继续尝试获取读锁。
if (getExclusiveOwnerThread() != current)
return -1;
// 如果写锁空闲,且可以获取读锁。
} else if (readerShouldBlock()) {
// 第一个读线程是当前线程
if (firstReader == current) {
// 如果不是当前线程
} else {
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
// 从 ThreadLocal 中取出计数器
rh = readHolds.get();
if (rh.count == 0)
readHolds.remove();
}
}
if (rh.count == 0)
return -1;
}
}
// 如果读锁次数达到 65535 ,抛出异常
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 尝试对 state 加 65536, 也就是设置读锁,实际就是对高16位加一。
if (compareAndSetState(c, c + SHARED_UNIT)) {
// 如果读锁是空闲的
if (sharedCount(c) == 0) {
// 设置第一个读锁
firstReader = current;
// 计数器为 1
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 = rh; // cache for release
}
return 1;
}
}
}