1、StampedLock特性
StampedLock是JDK 8新增的读写锁,跟读写锁不同,它并不是由AQS实现的。它的state为一个long型变量,状态的设计也不同于读写锁,且提供了三种模式来控制 read/write 的获取,并且内部实现了自己的同步等待队列。
1.1、StampedLock读写锁
写锁:使用writeLock方法获取,当锁不可用时会阻塞,获取成功后返回一个与这个写锁对应的stamp,在unlockWrite方法中,需要通过这个stamp来释放与之对应的锁。在tryWriteLock同样也会提供这个stamp。当在write模式中获取到写锁时,读锁不能被获取,并且所有的乐观读锁验证(validate方法)都会失败。
读锁:使用readLock方法获取,当超出可用资源时(类似AQS的state设计)会阻塞。同样的,在获取锁成功后也会返回stamp,作用与上述相同。tryReadLock同样如此。
乐观读锁:使用tryOptimisticRead方法获取,只有在写锁可用时才能成功获取乐观读锁,获取成功后也会返回一个stamp。validate方法可以根据这个stamp来判断写锁是否被获取。这种模式可以理解为一个弱化的读锁(weak version of a read-lock),它在任何时候都能被破坏。乐观读模式常被用在短的只读的代码段,用来减少争用并提高吞吐量。乐观读区域应该只读取字段,并将它们保存在本地变量中,以便在验证(validate方法)后使用。在乐观读模式中字段的读取可能会不一致,所以可能需要反复调用validate()来检查一致性。例如,当首次读取一个对象或数组引用,然后访问其中一个的字段、元素或方法时,这些步骤通常是必需的。
1.2、三种模式的转换
StampedLock可以将三种模式是锁进行有条件的互相转换。
将其他锁转换为写锁**tryConvertToWriteLock()**:
当前邮戳为持有写锁模式,直接返回当前的邮戳;
当前邮戳为持有读锁模式,则会释放读锁并获取写锁,并返回写锁邮戳;
当前邮戳持有乐观锁,通过CAS立即获取写锁,成功则返回写锁邮戳;失败则返回0;
将其他锁转换为读锁**tryConvertToReadLock**:
当前邮戳为持有写锁模式,则会释放写锁并获取读锁,并返回读锁邮戳;
当前邮戳为持有读锁模式,则直接返回当前读锁邮戳;
当前邮戳持有乐观锁,通过CAS立即获取读锁,则返回读锁邮戳;否则,获取失败返回0;
将其他锁转换为乐观锁**tryConvertToOptimisticRead**:
当前邮戳为持有读或写锁,则直接释放读写锁,并返回释放后的观察者邮戳值;
当前邮戳持有乐观锁,若乐观锁邮戳有效,则返回观察者邮戳;
1.3、StampedLock的应用场景
StampedLock一般作为线程安全的内部工具类。它的使用依赖于对数据、对象和方法的内部属性有一定的了解。StampedLock 是不可重入的,所以在锁的内部不能调用其他尝试重复获取锁的方。一个stamp如果在很长时间都没有使用或验证,在很长一段时间之后可能就会验证失败。StampedLocks是可序列化的,但是反序列化后变为初始的非锁定状态,所以在远程锁定中是不安全的。
1.4、StampedLock的公平性
StampedLock 的调度策略不会始终偏向读线程或写线程,所有的”try”方法都是尽最大努力获取,并不一定遵循任何调度或公平策略。从”try”方法获取或转换锁失败返回0时,不会携带任何锁的状态信息。由于StampedLock支持跨多个锁模式的协调使用,它不会直接实现Lock或ReadWriteLock接口。但是,如果应用程序需要Lock的相关功能,它可以通过asReadLock()、asWriteLock()和asReadWriteLock()方法返回一个Lock视图。
2、源码分析
2.1、主要属性
//获取CPU的可用线程数量,用于确定自旋的时候循环次数private static final int NCPU = Runtime.getRuntime().availableProcessors();//根据NCPU确定自旋的次数限制(并不是一定这么多次,因为实际代码中是随机的)private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0;//头节点上的自旋次数private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 0;//头节点上的最大自旋次数private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 0;//等待自旋锁溢出的周期数private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1//在溢出之前读线程计数用到的bit位数private static final int LG_READERS = 7;//一个读状态单位:0000 0000 0001private static final long RUNIT = 1L;//一个写状态单位:0000 1000 0000private static final long WBIT = 1L << LG_READERS;//读状态标识:0000 0111 1111private static final long RBITS = WBIT - 1L;//读锁计数的最大值:0000 0111 1110private static final long RFULL = RBITS - 1L;//读线程个数和写线程个数的掩码:0000 1111 1111private static final long ABITS = RBITS | WBIT;//// 读线程个数的反数,高25位全部为1:1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1000 0000private static final long SBITS = ~RBITS; // note overlap with ABITS// state的初始值private static final long ORIGIN = WBIT << 1;// 中断标识private static final long INTERRUPTED = 1L;// 节点状态值,等待/取消private static final int WAITING = -1;private static final int CANCELLED = 1;// 节点模式,读模式/写模式private static final int RMODE = 0;private static final int WMODE = 1;//等待队列的头节点private transient volatile WNode whead;//等待队列的尾节点private transient volatile WNode wtail;// 锁状态private transient volatile long state;////因为读状态只有7位很小,所以当超过了128之后将使用此变量来记录private transient int readerOverflow;
2.2、node节点实现
//等待队列的节点实现static final class WNode {//前驱节点volatile WNode prev;//后继节点volatile WNode next;//读线程使用的链表volatile WNode cowait; // list of linked readers//等待的线程volatile Thread thread; // non-null while possibly parked//节点状态volatile int status; // 0, WAITING, or CANCELLED//节点模式final int mode; // RMODE or WMODEWNode(int m, WNode p) { mode = m; prev = p; }}
2.3、state状态实现
state状态说明:
- bit0—bit6为作为读锁计数,当超出RFULL(126)时,用readerOverflow作为读锁计数。当获取到读锁时,state加RUINT(值为1);当释放读锁时,state减去RUINT。
- bit7为写锁标识,其值为1表示已获取写锁,值为0表示已获取读锁。当线程获取写锁或释放写锁时,都会将state加WBIT;
- bit8—bit64:表示写锁版本,不论获取写锁还是释放写锁,其值都会改变。
初始状态bit8为1,其他位为0。
state常用状态标识:
- RUNIT:
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 - WBIT:
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1000 0000 - RBITS:
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0111 1111 - RFULL:
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0111 1110 - ABITS:
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 - SBITS:
1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1000 0000 - ORIGIN:
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 0000 0000
state常用状态判断:
- 有无线程获取写状态:state < WBIT,true:无,false:有;
- 读状态是否溢出:(state & ABITS) < RFULL,true;否;false:是;
- 获取读状态: state + RUNIT(或者readerOverflow + 1)
- 获取写状态: state + WBIT
- 释放读状态: state - RUNIT(或者readerOverflow - 1)
- 释放写状态: (s += WBIT) == 0L ? ORIGIN : s
- 是否为写锁: (state & WBIT) != 0L
- 是否为读锁: (state & RBITS) != 0L
2.4、写锁获取及释放
获取写锁: ```java public long writeLock() { long s, next;
//(state & ABITS)获取低8位,判断有无读/写锁存在, //有其他读锁则bit0-bit6不为0,有其他写锁则bit7不为0, //因此如果有别的写锁或者读锁存在将失败 //尝试CAS获取写锁 //失败调用acquireWrite继续获取写锁 return ((((s = state) & ABITS) == 0L &&
}U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?next : acquireWrite(false, 0L));
private long acquireWrite(boolean interruptible, long deadline) { //node为当前节点,p为当前节点的前驱节点 WNode node = null, p;
// 第一次自旋——主要进行入队工作for (int spins = -1;;) { // spin while enqueuinglong m, s, ns;//(state&ABITS)为0表示无读/写锁,则尝试CAS获取写锁if ((m = (s = state) & ABITS) == 0L) {if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))return ns;}else if (spins < 0)// 如果自旋次数小于0,则计算自旋的次数// 如果当前有写锁(m == WBIT)独占,且队列无元素(wtail == whead),// 说明当前节点的前驱节点为获取独占锁的节点,锁很快就会释放,// 就自旋SPINS次就行了,如果自旋完了还没轮到自己才入队// 否则自旋次数为0spins = (m == WBIT && wtail == whead) ? SPINS : 0;else if (spins > 0) {// 当自旋次数大于0时,当前这次自旋随机减一次自旋次数if (LockSupport.nextSecondarySeed() >= 0)--spins;}else if ((p = wtail) == null) { // initialize queue// 如果队列未初始化,新建一个空节点并初始化头节点和尾节点WNode hd = new WNode(WMODE, null);if (U.compareAndSwapObject(this, WHEAD, null, hd))wtail = hd;}else if (node == null)// 如果新增节点还未初始化,则新建之,并赋值其前置节点为尾节点node = new WNode(WMODE, p);else if (node.prev != p)// 如果新增节点的前驱节点不是尾节点,// 则更新新增节点的前驱节点为新的尾节点node.prev = p;else if (U.compareAndSwapObject(this, WTAIL, p, node)) {// 尝试更新新增节点为新的尾节点成功,则退出循环p.next = node;break;}}// 第二次自旋——主要进行阻塞并等待唤醒for (int spins = -1;;) {// h为头节点,np为新增节点的前置节点,pp为前前置节点,ps为前置节点的状态WNode h, np, pp; int ps;// 如果头节点等于前置节点,说明快轮到自己了if ((h = whead) == p) {if (spins < 0)// 自旋次数小于0,则初始化自旋次数spins = HEAD_SPINS;else if (spins < MAX_HEAD_SPINS)// 自旋次数小于头结点最大自旋次数,则增加自旋次数spins <<= 1;// 第三次自旋,不断尝试获取写锁for (int k = spins;;) { // spin at headlong s, ns;//无读写锁则CAS获取写锁,成功则更新节点信息if (((s = state) & ABITS) == 0L) {if (U.compareAndSwapLong(this, STATE, s,ns = s + WBIT)) {whead = node;node.prev = null;return ns;}}// 随机立减自旋次数,当自旋次数减为0时跳出循环再重试else if (LockSupport.nextSecondarySeed() >= 0 &&--k <= 0)break;}}//头节点为空?else if (h != null) { // help release stale waitersWNode c; Thread w;// 如果头节点的cowait链表(栈)不为空,唤醒里面的所有节点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) {if (np != null)(p = np).next = node; // stale}else if ((ps = p.status) == 0)// 如果尾节点状态为0,则更新成WAITINGU.compareAndSwapInt(p, WSTATUS, 0, WAITING);else if (ps == CANCELLED) {// 如果尾节点状态为取消,则把它从链表中删除if ((pp = p.prev) != null) {node.prev = pp;pp.next = node;}}else {// 有超时时间的处理long time; // 0 argument to park means no timeoutif (deadline == 0L)time = 0L;//时间以过期则取消节点else if ((time = deadline - System.nanoTime()) <= 0L)return cancelWaiter(node, node, false);//设置线程blockerThread wt = Thread.currentThread();U.putObject(wt, PARKBLOCKER, this);node.thread = wt;//1、当前节点前驱节点状态为WAITING;//2、当前节点的前驱节点不是头节点或有读写锁已经被获取;//3、头结点为改变;//4、当前节点的前驱节点未改变;//当以上4个条件都满足时将当前节点进行阻塞if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&whead == h && node.prev == p)U.park(false, time); // emulate LockSupport.parknode.thread = null;//设置线程blocker为空U.putObject(wt, PARKBLOCKER, null);//当前节点百中断则取消节点if (interruptible && Thread.interrupted())return cancelWaiter(node, node, true);}}}
}
**写锁释放:**```javapublic void unlockWrite(long stamp) {WNode h;//因为写锁是独占锁,可以简单判断state != stamp;//或者bit7为0,即stamp状态为无写锁if (state != stamp || (stamp & WBIT) == 0L)throw new IllegalMonitorStateException();//修改state状态,state += WBIT;溢出则初始化为ORIGINstate = (stamp += WBIT) == 0L ? ORIGIN : stamp;//头节点不为空,且状态正常则释放头结点的锁if ((h = whead) != null && h.status != 0)release(h);}private void release(WNode h) {if (h != null) {WNode q; Thread w;//设置头节点状态为0U.compareAndSwapInt(h, WSTATUS, WAITING, 0);//头节点下个节点为空或状态为CANCEL,则从尾节点前向遍历,//找到头结点后面的第一个有效节点(状态为0或WAITTING)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 (q != null && (w = q.thread) != null)U.unpark(w);}}
2.5、读锁获取及释放
读锁获取:
public long readLock() {long s = state, next; // bypass acquireRead on common uncontended case//同步队列为空,读锁计数值未超过最大值(无写锁),CAS获取锁成功,则直接返回邮戳值;//否则acquireRead获取读锁return ((whead == wtail && (s & ABITS) < RFULL &&U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?next : acquireRead(false, 0L));}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 & ABITS)小于RFULL,表示无写锁,则直接CAS获取读锁;//否则若(state & ABITS)小于WBIT表示无写锁但读锁计数已溢出,//则CAS更新读锁计数获取读锁if ((m = (s = state) & ABITS) < RFULL ?U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L))return ns;//(state & ABITS)大于WBIT,表示写锁已经被占,则自旋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;}//初始化spinsspins = SPINS;}}}}//自旋获取失败,则进行节点初始化相关的处理//尾节点为空,则初始化队列if (p == null) { // initialize queueWNode hd = new WNode(WMODE, null);if (U.compareAndSwapObject(this, WHEAD, null, hd))wtail = hd;}//初始化代表当前读线程的节点else if (node == null)node = new WNode(RMODE, p);//head==tail或者队列tail.mode不为读状态,//那么将当前线程的节点node加入到队列尾部并跳出外层循环else if (h == p || p.mode != RMODE) {if (node.prev != p)node.prev = p;else if (U.compareAndSwapObject(this, WTAIL, p, node)) {p.next = node;break;}}//如果head!= tail说明队列中已经有线程在等待或者tail.mode是读状态RMODE,//那么CAS方式将当前线程的节点node加入到tail节点的cowait链中else if (!U.compareAndSwapObject(p, WCOWAIT,node.cowait = p.cowait, node))node.cowait = null;else {for (;;) {WNode pp, c; Thread w;////如果head不为空那么尝试去解放head的cowait链中的节点if ((h = whead) != null && (c = h.cowait) != null &&U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&(w = c.thread) != null) // help releaseU.unpark(w);//如果tail节点的前驱就是head或者head==tail或者tail节点的前驱是null//也就是说当前node所在的节点(因为node可能在cowait链中)//的前驱就是head或者head已经被释放了为nullif (h == (pp = p.prev) || h == p || pp == null) {long m, s, ns;do {//如果没有写状态被占有那么自旋方式尝试获取读状态,成功则返回stampif ((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;//如果tail的前驱是null或者head==tail或者tail已经被取消了(p.status > 0)//直接将node置为null跳出循环,回到最开的for循环中去再次尝试获取同步状态if (pp == null || h == p || p.status > 0) {node = null; // throw awaybreak;}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;//tail的前驱不是head或者当前只有写线程获取到同步状态//判断稳定性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);}}}}//如果队列中没有节点或者tail的mode是WMODE写状态,//那么node被加入到队列的tail之后进入这个循环for (int spins = -1;;) {WNode h, np, pp; int ps;//如果p(node的前驱节点)就是head,那么自旋方式尝试获取同步状态if ((h = whead) == p) {//第一次循环,设置自旋次数if (spins < 0)spins = HEAD_SPINS;//自旋次数增加else if (spins < MAX_HEAD_SPINS)spins <<= 1;for (int k = spins;;) { // spin at headlong m, s, ns;//自旋方式尝试获取同步状态//获取成功的话将node设置为head并解放node的cowait链中的节点并返回stampif ((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;}//如果有写线程获取到了同步状态(因为可能有写线程闯入)那么随机的--k控制循环次数else if (m >= WBIT &&LockSupport.nextSecondarySeed() >= 0 && --k <= 0)break;}}//如果head不为null,解放head的cowait链中的节点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) {if (np != null)(p = np).next = node; // stale}//尝试设tail的状态位WAITING表示后面还有等待的节点else if ((ps = p.status) == 0)U.compareAndSwapInt(p, WSTATUS, 0, WAITING);//如果tail已经取消了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);}}}}
读锁释放:
public void unlockRead(long stamp) {long s, m; WNode h;for (;;) {//写计数相关的bit位有改变,或读计数相关的bit位为0,或有写锁,则异常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;}}
2.6、乐观锁获取
public long tryOptimisticRead() {long s;//当无写锁,则返回(state & SBITS),即高位的写计数;//否则返回0,即获取乐观锁失败return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;}
2.7、锁模式的转换
转换为写锁:将其他模式(如写锁、读锁、乐观锁)的锁转换为写锁
public long tryConvertToWriteLock(long stamp) {long a = stamp & ABITS, m, s, next;//写锁的状态未变?while (((s = state) & SBITS) == (stamp & SBITS)) {//当前无写/读锁?CAS获取写锁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;}//无写锁,有一个读锁,即当前线程为获取读锁的线程//直接cas将读锁释放并获取写锁,即state=(state - RUNIT + WBIT)else if (m == RUNIT && a != 0L) {if (U.compareAndSwapLong(this, STATE, s,next = s - RUNIT + WBIT))return next;}//当还有其他线程获取读锁时,自旋等待其他读锁释放elsebreak;}return 0L;}
主要处理:
当锁状态为无读/写锁时,通过CAS获取写锁;
当当前线程已获取写锁时,直接返回原本的邮戳;
当只有一个读锁,即当只有当前线程获取读锁,没有其他的读锁时,CAS释放读锁并获取写锁;
当获取读锁的线程数大于1,即除当前线程还有其他线程也获取到读锁时,自旋等待其他读锁释放;
转换为读锁:将读/写锁转换为读锁;
public long tryConvertToReadLock(long stamp) {long a = stamp & ABITS, m, s, next; WNode h;//无写锁?while (((s = state) & SBITS) == (stamp & SBITS)) {//无读/写锁,则CAS获取读锁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);if ((h = whead) != null && h.status != 0)release(h);return next;}//当前线程已经获取得读锁?else if (a != 0L && a < WBIT)return stamp;elsebreak;}return 0L;}
主要处理:
若无读/写锁,则CAS获取读锁;
若写锁为当前线程,则CAS释放写锁并获取读锁;
若当前线程已经获取读锁,则返回原本的邮戳;
转换为乐观锁:
public long tryConvertToOptimisticRead(long stamp) {long a = stamp & ABITS, m, s, next; WNode h;U.loadFence();for (;;) {//写锁状态变更?if (((s = state) & SBITS) != (stamp & SBITS))break;//无读/写锁?直接返回stateif ((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;}
主要处理:
若当前线程已经获取写锁,则直接释放写锁;
若当前线程已经获取读锁,则CAS释放读锁;
当锁时,返回状态值state;
