前提
1.WNode源码分析
static final class WNode {
volatile WNode prev; //节点的前置连接
volatile WNode next; //节点的后置连接
volatile WNode cowait; //连续读节点的等待队列
volatile Thread thread;
volatile int status; // 0, WAITING, or CANCELLED
final int mode; // RMODE or WMODE (读节点或者写节点)
WNode(int m, WNode p) { mode = m; prev = p; }
}
WNode中的pre与next代表的是等待队列的链表形态,队列包含写节点与读节点,而cowait代表的连续读节点的等待队列的链表形态;
WNode中的status有3中,0代表中间状态,-1代表后续有节点阻塞等待,1代表当前节点任务取消;
WNode中的mode有两种,RMODE=0代表读节点,WNode=1代表写节点;
WNode的构造函数,以节点类型和前置节点进行创建;
2.StampedLock中的state同步状态值采用分段的方式提供不同的功能,从右开始的7位代表的是读锁的同步状态,第8位代表写锁的同步状态,剩下的56位代表的是锁的版本号(邮戳);
3.state默认值为ORIGIN,也就是256,二进制1 0000 0000,这里代表版本号起始为1,且锁为空闲状态;
一、WriteLockView(独占写锁)
final class WriteLockView implements Lock {
public void lock() { writeLock(); }
public void unlock() { unstampedUnlockWrite(); }
}
public long writeLock() {
long s, next;
//这里的ABITS为255,二进制为1111 1111,state&ABITS代表的是去state的后8位
//后8位的值是0代表写锁空闲
return ((((s = state) & ABITS) == 0L &&
//这里的WBIT为128,二进制为1000 0000,这里的操作其实是在state第8位加1
U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
next : acquireWrite(false, 0L));
}
//interruptible代表中断发生后是否退出竞争(true退出竞争,false继续竞争)
//deadline代表等待的最大时间
private long acquireWrite(boolean interruptible, long deadline) {
WNode node = null, p;
for (int spins = -1;;) { // 自旋入队操作 spins为自旋数
long m, s, ns;
//如果当前写锁空闲,就自旋获取锁
if ((m = (s = state) & ABITS) == 0L) {
if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
return ns;
}//在写锁占用的情况情况下,由于spins默认为-1,这里会进入对spins初始化
else if (spins < 0)
//当写锁为占用状态(state后8位为1000 0000)并且等待队列为空的情况下为64
//这里的SPINS还要判断硬件能力,多核为64次,否则为0
spins = (m == WBIT && wtail == whead) ? SPINS : 0;
else if (spins > 0) {//自旋逐减的操作
//通过随机数判断,可以让线程自旋数不一致
if (LockSupport.nextSecondarySeed() >= 0)
--spins;
}
else if ((p = wtail) == null) { //当队列为空的情况下,插入哨兵节点
WNode hd = new WNode(WMODE, null);//创建一个前置为null,写类型的节点
if (U.compareAndSwapObject(this, WHEAD, null, hd))//将该节点放入队列中
wtail = hd;
}
注1️⃣
else if (node == null)//初始化我们要放入等待队列的当前线程节点
node = new WNode(WMODE, p);//类型为写节点,前置节点为队列尾节点
else if (node.prev != p)//当node的前置节点发生变化时,重置node的前置节点
node.prev = p;
else if (U.compareAndSwapObject(this, WTAIL, p, node)) {//将尾结点置为node
p.next = node;//原尾结点的后置节点指向node,退出自旋
break;
}
}
//在上面自旋完成入队操作后
for (int spins = -1;;) {
WNode h, np, pp; int ps;
//h重新指向队列头节点,当队列等于p,并不是队列为空的意思
//这里代表的是node前置节点成为了头节点
if ((h = whead) == p) {注2️⃣
if (spins < 0)//初始化自旋数为1024
spins = HEAD_SPINS;
else if (spins < MAX_HEAD_SPINS)//当自旋数小于65535就自乘以2
spins <<= 1;
for (int k = spins;;) { //开始自旋
long s, ns;
if (((s = state) & ABITS) == 0L) {//写锁状态为空闲
if (U.compareAndSwapLong(this, STATE, s,
ns = s + WBIT)) {//cas操作state成功
whead = node;//将头节点置为node,node的前置置为null,返回ns
node.prev = null;
return ns;
}
}
else if (LockSupport.nextSecondarySeed() >= 0 &&
--k <= 0)//写锁专用情况下,自旋逐减
break;
}
}
else if (h != null) { //这里头节点不是空的且不是node的前置节点
WNode c; Thread w;//会唤醒在头结点上等待的所有读节点
while ((c = h.cowait) != null) {
if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
(w = c.thread) != null)
U.unpark(w);
}
}
if (whead == h) {//头结点没有发生变化的情况下
if ((np = node.prev) != p) {
//node的前置节点p发生改变,重置p,将p的后置节点指向node
if (np != null)
(p = np).next = node; // stale
}
else if ((ps = p.status) == 0)//前置节点从中间状态变为等待状态
U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
else if (ps == CANCELLED) {//前置节点为取消状态
if ((pp = p.prev) != null) {
//状态前置节点的前置节点pp,将pp与node相连,去掉p节点
node.prev = pp;
pp.next = node;
}
}
else {//这里进入阻塞阶段
long time;
if (deadline == 0L)//0代表没有时间限制,可以无限等待
time = 0L;
//这里已经超出最大时间了,取消当前节点
else if ((time = deadline - System.nanoTime()) <= 0L)
return cancelWaiter(node, node, false);
Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this);//设置线程阻塞对象
node.thread = wt;
/*当前置节点为-1并且前置节点不是头结点且写锁为占用状态,头节点与node的前
置节点没有发生变化的情况下,阻塞当前线程*/
if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
whead == h && node.prev == p)
U.park(false, time); // emulate LockSupport.park
node.thread = null;//醒来后,将节点线程置为null
U.putObject(wt, PARKBLOCKER, null);//线程阻塞对象置为null
if (interruptible && Thread.interrupted())//如果当断后处理为取消竞争
//发生中断后,这里会将当前节点任务取消掉
注3️⃣
return cancelWaiter(node, node, true);
}
}
}
}
final void unstampedUnlockWrite() {
WNode h; long s;
if (((s = state) & WBIT) == 0L)//如果写锁未占用,则抛出异常
throw new IllegalMonitorStateException();
state = (s += WBIT) == 0L ? ORIGIN : s;//这里加128是为了进位修改版本号
if ((h = whead) != null && h.status != 0)
//当头结点不是空且状态不为0,唤醒后续节点
release(h);
}
注意:
1.在注1的地方的3个分支处理,就是第一个自旋入队的操作,这里使用自旋是因为这是一个双向链表,插入到队列尾,需要两步改变,一步是node的前置节点的链接改变,另一步是node的前置节点的后置节点的链接改;这里可以看到先是node前置节点的指向队列尾节点,再把队列尾结点指针指向node后,最后将原尾结点的后置节点指向node,这是由于存在竞争的条件下,多个node会争抢修改队列尾指针指向,尾指针修改采用cas操作,修改失败的node会在下次循环会重置自己的前置节点,避免节点消失的问题。
2.在注2的地方的if处理中,里面是个自旋操作,这里的意义代表当node的前置节点为头结点时,代表node的前置节点抢到了资源,可能很快就到你了,不需要阻塞,所以这里有个自旋获取锁的操作,还有一点要注意,里面的自旋数的递增的,每次都是上一次自旋数的2倍,达到自旋最大值65536后就不会增加了,这样做的目的是为了线程利用率,保证每个线程获取资源的时间平均些。
3.注3的地方的取消节点操作,这里进行详细说明
private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
if (node != null && group != null) {
Thread w;
node.status = CANCELLED;//node节点状态置为取消
//连续读节点组中取消节点剔除
for (WNode p = group, q; (q = p.cowait) != null;) {
if (q.status == CANCELLED) {
U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
p = group; // restart
}
else
p = q;
}
//连续读节点组等于node本身代表node是等待队列中的节点
if (group == node) {
for (WNode r = group.cowait; r != null; r = r.cowait) {
if ((w = r.thread) != null)
U.unpark(w); //唤醒读节点
}
//将node的前后包括本身的取消节点剔除队列
for (WNode pred = node.prev; pred != null; ) {
WNode succ, pp;
//剔除node后面的取消节点
while ((succ = node.next) == null ||
succ.status == CANCELLED) {
WNode q = null;
//从尾节点往前找node后的第一个正常节点
for (WNode t = wtail; t != null && t != node; t = t.prev)
if (t.status != CANCELLED)
q = t;
//将node与后面的正常节点相连,剔除取消节点
if (succ == q ||
U.compareAndSwapObject(node, WNEXT,
succ, succ = q)) {
if (succ == null && node == wtail)
U.compareAndSwapObject(this, WTAIL, node, pred);
break;
}
}
if (pred.next == node) //将前置节点与node后面的正常节点相连
U.compareAndSwapObject(pred, WNEXT, node, succ);
if (succ != null && (w = succ.thread) != null) {
succ.thread = null;
U.unpark(w);//唤醒node后的正常节点,让他去修改自己的前置节点
}
if (pred.status != CANCELLED || (pp = pred.prev) == null)
break;
node.prev = pp;//如果前置节点为取消节点,这里会剔除前置节点,并向前继续
U.compareAndSwapObject(pp, WNEXT, pred, succ);
pred = pp;
}
}
}
WNode h;
while ((h = whead) != null) {//这里剔除头节点后的取消节点
long s; WNode q;
if ((q = h.next) == null || q.status == CANCELLED) {
for (WNode t = wtail; t != null && t != h; t = t.prev)
if (t.status <= 0)
q = t;
}
if (h == whead) {//头节点无变化
//头结点的后继节点符号条件,就唤醒
//条件:后继节点不为空且状态中立且写锁空闲且(后继节点为读节点或者锁空闲)
if (q != null && h.status == 0 &&
((s = state) & ABITS) != WBIT &&
(s == 0L || q.mode == RMODE))
release(h);
break;
}
}
return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
}
这里取消节点的操作主要是从队列中剔除,一个是从连续读节点队列中剔除,一个是从等待队列中剔除,但不只是剔除本身,还有队列中的其他取消节点。
二、ReadLockView(共享读锁)
final class ReadLockView implements Lock {
public void lock() { readLock(); }
public void unlock() { unstampedUnlockRead(); }
}
public long readLock() {
long s = state, next;
//队列为空,且state取后8位,小于126时才可以直接获取读锁,不成功进入acuqireRead方法
return ((whead == wtail && (s & ABITS) < RFULL && //RFULL=126
U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
next : acquireRead(false, 0L));
}
//interruptible代表中断发生后是否退出竞争(true退出竞争,false继续竞争)
//deadline代表等待的最大时间
private long acquireRead(boolean interruptible, long deadline) {
WNode node = null, p;
for (int spins = -1;;) {//自旋入队操作
WNode h;
if ((h = whead) == (p = wtail)) {//等待队列为空的情况下,自旋获取锁
for (long m, s, ns;;) {
//当state的后8位小于126,获取锁
//大于等于126小于128的话,可以获取读锁,溢出值变为1,state后8位为127
//大于等于128,代表有写锁处于占用状态,会周期性的让出线程的执行权
if ((m = (s = state) & ABITS) < RFULL ?
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L))
return ns;
else if (m >= WBIT) {//有写锁处于占用状态
if (spins > 0) {//自旋逐减
if (LockSupport.nextSecondarySeed() >= 0)
--spins;
}
else {
if (spins == 0) {//自旋完成后
WNode nh = whead, np = wtail;
//头尾节点未发生变化,或者队列不为空,退出自旋
if ((nh == h && np == p) || (h = nh) != (p = np))
break;
}
spins = SPINS;//初始化spins
}
}
}
}
if (p == null) { //设置前置为null,类型为写类型的哨兵节点进入等待队列
WNode hd = new WNode(WMODE, null);
if (U.compareAndSwapObject(this, WHEAD, null, hd))
wtail = hd;
}
else if (node == null)//初始化当前线程的节点
node = new WNode(RMODE, p);//读类型,前置节点为队列尾结点
//队列为空(这里包括有哨兵节点的队列)或者尾结点的类型为写节点
else if (h == p || p.mode != RMODE) {
if (node.prev != p)//当队列尾结点发生变化,将node的前置节点重置
node.prev = p;
//node前置节点无变化,这里修改尾节点指针指向node,原尾结点的后置节点为node
else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
p.next = node;
break;//入队成功,退出循环了
}
}
//这里也是一个入队操作,不过是针对连续读节点的
//当尾结点也是读节点时,将node置入尾结点的cowait队列中
//这里node会成为尾结点的直接cowait节点,以前的cowait节点成为node的cowait节点
else if (!U.compareAndSwapObject(p, WCOWAIT,
node.cowait = p.cowait, node))
node.cowait = null;
else {//这里是连续节点入队完成后,会自旋阻塞,这个阻塞不会修改前置节点的状态
for (;;) {//自旋
WNode pp, c; Thread w;
if ((h = whead) != null && (c = h.cowait) != null &&
U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
(w = c.thread) != null) //唤醒头结点上的连续读节点
U.unpark(w);
//由于连续读节点时挂在一个读节点上的,所以这里多判断了node前置节点的前置
//节点为头结点的情况
if (h == (pp = p.prev) || h == p || pp == null) {
long m, s, ns;
do {//读锁未达到获取上线,自旋获取
if ((m = (s = state) & ABITS) < RFULL ?
U.compareAndSwapLong(this, STATE, s,
ns = s + RUNIT) :
(m < WBIT &&
(ns = tryIncReaderOverflow(s)) != 0L))
return ns;
} while (m < WBIT);
}//头结点无变化且前置节点的前置节点无变化
if (whead == h && p.prev == pp) {
long time;
//pp为null或者p为取消节或者p为头节点,将不阻塞线程,退出自旋
if (pp == null || h == p || p.status > 0) {
node = null; // throw away
break;
}
if (deadline == 0L)
time = 0L;
else if ((time = deadline - System.nanoTime()) <= 0L)
return cancelWaiter(node, p, false);
Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this);
node.thread = wt;
//头结点不是pp或者写锁占用状态并且头节点与pp无变化,阻塞当前线程
if ((h != pp || (state & ABITS) == WBIT) &&
whead == h && p.prev == pp)
U.park(false, time);
node.thread = null;
U.putObject(wt, PARKBLOCKER, null);
if (interruptible && Thread.interrupted())
return cancelWaiter(node, p, true);
}
}
}
}
for (int spins = -1;;) {
WNode h, np, pp; int ps;
if ((h = whead) == p) {//当node前置节点为头节点时
if (spins < 0)//初始化spins
spins = HEAD_SPINS;
else if (spins < MAX_HEAD_SPINS)
spins <<= 1;
for (int k = spins;;) { // spin at head
long m, s, ns;
if ((m = (s = state) & ABITS) < RFULL ?
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
WNode c; Thread w;
whead = node;
node.prev = null;
while ((c = node.cowait) != null) {
if (U.compareAndSwapObject(node, WCOWAIT,
c, c.cowait) &&
(w = c.thread) != null)
U.unpark(w);
}
return ns;
}
else if (m >= WBIT &&
LockSupport.nextSecondarySeed() >= 0 && --k <= 0)
break;
}
}
else if (h != null) {//唤醒头结点上连续的读节点
WNode c; Thread w;
while ((c = h.cowait) != null) {
if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
(w = c.thread) != null)
U.unpark(w);
}
}
if (whead == h) {//头结点无变化
if ((np = node.prev) != p) {//node前置发生变化重置
if (np != null)
(p = np).next = node;
}
else if ((ps = p.status) == 0)//将前置的状态设为-1
U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
else if (ps == CANCELLED) {//剔除取消节点
if ((pp = p.prev) != null) {
node.prev = pp;
pp.next = node;
}
}
else {//进入阻塞线程流程
long time;
if (deadline == 0L)
time = 0L;
else if ((time = deadline - System.nanoTime()) <= 0L)
return cancelWaiter(node, node, false);
Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this);
node.thread = wt;
if (p.status < 0 &&
(p != h || (state & ABITS) == WBIT) &&
whead == h && node.prev == p)
U.park(false, time);
node.thread = null;
U.putObject(wt, PARKBLOCKER, null);
if (interruptible && Thread.interrupted())
return cancelWaiter(node, node, true);
}
}
}
}
final void unstampedUnlockRead() {
for (;;) {
long s, m; WNode h;
//这里是读锁未获取或者写锁占用的情况,抛出异常
if ((m = (s = state) & ABITS) == 0L || m >= WBIT)
throw new IllegalMonitorStateException();
else if (m < RFULL) {//读锁数量小于126,state-1
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
//只有队列中有一个节点时,才会进行唤醒
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
break;
}
}//溢出的情况,释放锁要将溢出值置为0
else if (tryDecReaderOverflow(s) != 0L)
break;
}
}
三、ReadWriteLockView(读写锁)
final class ReadWriteLockView implements ReadWriteLock {
public Lock readLock() { return asReadLock(); }
public Lock writeLock() { return asWriteLock(); }
}
public Lock asReadLock() {
ReadLockView v;
return ((v = readLockView) != null ? v :
(readLockView = new ReadLockView()));
}
public Lock asWriteLock() {
WriteLockView v;
return ((v = writeLockView) != null ? v :
(writeLockView = new WriteLockView()));
}
这个模式是上面两个模式的集合体,没有什么特殊的地方。
四、辅助方法
tryOptimisticRead()&validate()
public long tryOptimisticRead() {
long s;
//获取第8位的值,写锁状态空闲,返回一个版本号,否则为0
return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
}
public boolean validate(long stamp) {
U.loadFence();
//这里SBITS二进制为57个1加上7个0,这里&操作获取的是版本号,当版本号没有发生变化时,返回true
return (stamp & SBITS) == (state & SBITS);
}
乐观读tryOptimisticRead是不上锁的,当我们使用乐观读时会返回一个版本号,这个版本号在我们做读操作之前进行验证,验证使用validate方法,true代表没有竞争,我们读取即可,否则代表已经出现竞争,读取就需要加共享读锁(ReadLock)了。
unlockRead(stamp)&unlock(stamp)&unlockWrite(stamp)
public void unlockRead(long stamp) {
long s, m; WNode h;
for (;;) {
//这里比unstampedUnlockRead多了对stamp的判断
//主要是版本号一致判断以及stamp锁状态判断
if (((s = state) & SBITS) != (stamp & SBITS) ||
(stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT)
throw new IllegalMonitorStateException();
if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
break;
}
}
else if (tryDecReaderOverflow(s) != 0L)
break;
}
}
public void unlockWrite(long stamp) {
WNode h;
//也是多了stamp判断,这里直接判断stamp==state,因为写锁的独占模式的
if (state != stamp || (stamp & WBIT) == 0L)
throw new IllegalMonitorStateException();
state = (stamp += WBIT) == 0L ? ORIGIN : stamp;
if ((h = whead) != null && h.status != 0)
release(h);
}
public void unlock(long stamp) {
long a = stamp & ABITS, m, s; WNode h;
//判断版本号是否一致
while (((s = state) & SBITS) == (stamp & SBITS)) {
//没有持有锁就退出循环,直接抛异常
if ((m = s & ABITS) == 0L)//m是state的后8位
break;
else if (m == WBIT) {//写锁释放
if (a != m)
break;
state = (s += WBIT) == 0L ? ORIGIN : s;
if ((h = whead) != null && h.status != 0)
release(h);
return;
}
//这里a是stamp的后8位 注1️⃣
else if (a == 0L || a >= WBIT)
break;
else if (m < RFULL) {//读锁释放
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return;
}
}//溢出值处理
else if (tryDecReaderOverflow(s) != 0L)
return;
}
throw new IllegalMonitorStateException();
}
注1的地方我们发现这里的a>=WBIT,是写锁判断的意思,但是上面已经判断过了,这里为什么还有判断呢,其实上面的判断是state的写锁判断,而注1的地方判断的是你邮戳的写锁判断,这是有可能出现,比如你调用了两次unlock就会进入这个判断。
tryConvertToReadLock(stamp)
public long tryConvertToReadLock(long stamp) {
long a = stamp & ABITS, m, s, next; WNode h;
while (((s = state) & SBITS) == (stamp & SBITS)) {//锁的版本号没有发生改变
if ((m = s & ABITS) == 0L) {//锁是空闲状态
if (a != 0L)//锁过期的情况
break;
else if (m < RFULL) {//读锁未达到上线,转化为读锁
if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
return next;
}
else if ((next = tryIncReaderOverflow(s)) != 0L)//溢出转换
return next;
}
else if (m == WBIT) {//写锁转换
if (a != m)//锁过期的情况
break;
state = next = s + (WBIT + RUNIT);//这里将写锁位置为0空闲,读锁位+1
if ((h = whead) != null && h.status != 0)//唤醒后续节点
release(h);
return next;
}
else if (a != 0L && a < WBIT)//本身就是读锁
return stamp;
else
break;
}
return 0L;
}
写锁转化为读锁,本质是对state的修改,这里写锁的释放会唤醒后续等待节点,转化失败不会阻塞。
tryConvertToWriteLock(stamp)
public long tryConvertToWriteLock(long stamp) {
long a = stamp & ABITS, m, s, next;
while (((s = state) & SBITS) == (stamp & SBITS)) {
if ((m = s & ABITS) == 0L) {//锁空闲状态
if (a != 0L)//锁过期
break;
if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))//写锁占用
return next;
}
else if (m == WBIT) {//本身为写锁
if (a != m)
break;
return stamp;
}
else if (m == RUNIT && a != 0L) {//读锁转换
if (U.compareAndSwapLong(this, STATE, s,//读锁位-1,写锁位+1
next = s - RUNIT + WBIT))
return next;
}
else
break;
}
return 0L;
}
读锁转化为写锁,其实本质是对state的修改,将读锁释放,获取写锁,这里没有等待唤醒机制,转化失败就失败了,不会阻塞的。
tryConvertOptimisticRead(stamp)
public long tryConvertToOptimisticRead(long stamp) {
long a = stamp & ABITS, m, s, next; WNode h;
U.loadFence();
for (;;) {
if (((s = state) & SBITS) != (stamp & SBITS))//版本号发生变化,退出循环
break;
if ((m = s & ABITS) == 0L) {//无锁情况
if (a != 0L)
break;
return s;
}
else if (m == WBIT) {//写锁占用状况,释放写锁,转化为乐观读
if (a != m)
break;
state = next = (s += WBIT) == 0L ? ORIGIN : s;
if ((h = whead) != null && h.status != 0)
release(h);
return next;
}
else if (a == 0L || a >= WBIT)//锁过期
break;
else if (m < RFULL) {//释放共享读锁,转化为乐观读
if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return next & SBITS;
}
}//减掉溢出值释放读锁后,转化为乐观读
else if ((next = tryDecReaderOverflow(s)) != 0L)
return next & SBITS;
}
return 0L;
}
读写转化为乐观读,其实都是需要先释放本身的锁后,才能使用乐观读,乐观读本质上是无锁状态读。