目录
一、WriteLockView
1、lock / lockInterruptibly
2、tryLock
3、unlock
4、unlockWrite / tryUnlockWrite
二、ReadLockView
1、lock / lockInterruptibly
2、tryLock
3、unlock
4、unlockRead / tryUnlockRead
三、乐观读锁
四、锁转换
1、tryConvertToWriteLock / tryConvertToReadLock /tryConvertToOptimisticRead
2、unlock
上一篇《Java8 StampedLock(一) 源码解析》详细讲解了该类的定义,具体的用法以及同ReentrantReadWriteLock的差异,本篇博客就详细分析源码实现细节。
相比ReentrantReadWriteLock的实现,StampedLock增加了基于for循环的自旋等待,在加入到同步链表前会自旋等待最多64次,加入到链表后,如果当前节点的前一个节点就是head节点,也会自旋等待,自旋的次数从1024次开始,每次for循环都会判断前一个节点是否还是head节点,如果是则将其扩容一倍,直到达到最大值65536次,每次自旋等待都会尝试获取锁。增加自旋等待的目的是为了减少线程休眠,线程上下文切换带来的性能损耗,提高抢占锁的效率。注意上述的最大自旋次数并不是实际的CPU自旋次数,因为只有当生成的随机数大于0时才认为是一次有效自旋,否则继续下一次的for循环。
另外StampedLock的写锁不支持重入,当一个阻塞状态的节点被唤醒后会将thread属性置为null,即当前head节点的thread属性为null,无法将该属性与当前线程比较,无法判断是否当前线程持有的写锁。
public void lock() { writeLock(); }
public void lockInterruptibly() throws InterruptedException {
writeLockInterruptibly();
}
public long writeLock() {
long s, next; // bypass acquireWrite in fully unlocked case only
return ((((s = state) & ABITS) == 0L && //等于0表示锁未被占用
//compareAndSwapLong返回true,表示原子修改成功,抢占锁成功
U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
//上述两个条件不成立表示需要进入等待队列了
next : acquireWrite(false, 0L));
}
public long writeLockInterruptibly() throws InterruptedException {
long next;
if (!Thread.interrupted() &&
(next = acquireWrite(true, 0L)) != INTERRUPTED)
return next;
//如果线程中断了则抛出异常
throw new InterruptedException();
}
//interruptible表示是否检查线程中断,deadline表示等待的最后时间,如果无期限则是0
private long acquireWrite(boolean interruptible, long deadline) {
WNode node = null, p;
//将加入链表的动作分解成多步,每一步都是一次for循环,每次都会尝试抢占锁,从而提高抢占锁的效率
for (int spins = -1;;) { // spin while enqueuing
long m, s, ns;
if ((m = (s = state) & ABITS) == 0L) {
//如果锁未被占用,尝试获取锁
if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
//获取成功
return ns;
}
else if (spins < 0)
//m是且运算后的结果,等于WBIT说明该写锁已经被占用了
//wtail和whead相等,可能都是null,也可能是某个节点,总之此时只有一个线程占有锁,所以就自旋等待该线程释放锁
spins = (m == WBIT && wtail == whead) ? SPINS : 0;
else if (spins > 0) {
//在上一个if分支初始化spins后再for循环,如果锁未释放则进入此分支
//通过nextSecondarySeed获取一个随机数,如果大于0,则将spins减一,否则继续下一次for循环
//会不断for循环直到spins变成0
if (LockSupport.nextSecondarySeed() >= 0)
--spins;
}
else if ((p = wtail) == null) { //spins等于0是会进入此分支
//创建一个空节点,原子的修改whead和wtail指向该节点
WNode hd = new WNode(WMODE, null);
if (U.compareAndSwapObject(this, WHEAD, null, hd))
wtail = hd;
}
else if (node == null)
//whead和wtail都初始化后进入此分支
node = new WNode(WMODE, p);
else if (node.prev != p)
//node赋值了,prev属性未赋值时进入此分支
node.prev = p;
else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
//node的prev属性赋值了,将其原子的设置为wtail,插入到原来的tail的后面
p.next = node;
break;
}
} //for循环结束
//上面的for循环在多次尝试获取锁后用当前线程创建一个WNode并插入到链表末尾
for (int spins = -1;;) {
WNode h, np, pp; int ps;
//p就是原来的wtail节点,whead等于p说明下一个被唤醒的节点就是node,通过自旋等待现在的whead节点对应的线程释放锁
if ((h = whead) == p) {
if (spins < 0)
//初始化spins
spins = HEAD_SPINS;
else if (spins < MAX_HEAD_SPINS)
//将spins左移一位,即扩大一倍
spins <<= 1;
//spins通过外层for循环达到最大值后,还是会自旋,只是自旋的次数不在增长了
for (int k = spins;;) { //通过for循环自旋spin次,每次都尝试获取锁
long s, ns;
if (((s = state) & ABITS) == 0L) {
if (U.compareAndSwapLong(this, STATE, s,
ns = s + WBIT)) {
//尝试获取锁成功则返回
whead = node;
node.prev = null;
return ns;
}
}
else if (LockSupport.nextSecondarySeed() >= 0 &&
//如果返回的随机值大于0,将k减1,直到k小于0,for循环退出
--k <= 0)
break;
}//for循环结束
}else if (h != null) { //还有其他的等待节点
WNode c; Thread w;
//遍历whead的cowait链表中的节点,将其对应的线程唤醒
//cowait链表中的元素是获取读锁时插入的,里面的节点都是获取读锁的线程
//此处将他们唤醒,他们也会自旋等待head节点释放锁
while ((c = h.cowait) != null) {
if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && //将whead的cowait属性设置为该链表的下一个元素
(w = c.thread) != null)
U.unpark(w);
}
}
//如果whead不等于p,有其他的等待节点
if (whead == h) {
//链表头没有改变,即未释放锁,如果变了就通过下一轮for循环抢占锁
if ((np = node.prev) != p) {
//node前面的节点变了
if (np != null)
(p = np).next = node; // stale
}
else if ((ps = p.status) == 0)
//将状态原子的修改为WAITING
U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
else if (ps == CANCELLED) {
//node的前一个节点的状态是CANCELLED,将其移除,通过外层的for循环将连续的多个CANCELLED节点删除
if ((pp = p.prev) != null) {
node.prev = pp;
pp.next = node;
}
}else {
//前面一个节点的状态是WAITING,肯定不是CANCELLED和0
long time; // 0 argument to park means no timeout
if (deadline == 0L)
time = 0L;
else if ((time = deadline - System.nanoTime()) <= 0L)
//如果剩余时间不足,将其标记成CANCELLED
return cancelWaiter(node, node, false);
Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this);
node.thread = wt;
if (p.status < 0 //p的状态是WAITING
&& (p != h || (state & ABITS) != 0L) //当前锁被其他线程占用了
&& whead == h //whead节点没有变动
&& node.prev == p) //node的上一个节点没有变动
U.park(false, time); //将当前线程阻塞掉
//线程被唤醒或者上面的if条件不成立
node.thread = null;
U.putObject(wt, PARKBLOCKER, null);
if (interruptible && Thread.interrupted())//如果线程被中断了
return cancelWaiter(node, node, true);
}
}
} //for循环结束
}
private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
if (node != null && group != null) {
Thread w;
//将状态置为CANCELLED
node.status = CANCELLED;
//遍历group的cowait链表,如果节点是CANCELLED,将其从链表中移除
for (WNode p = group, q; (q = p.cowait) != null;) {
if (q.status == CANCELLED) {
U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
p = group; //从group开始重新遍历
}
else
//遍历链表中下一个元素
p = q;
}
//acquireWrite调用时这两个是一样的
if (group == node) {
//唤醒group cowait链表中所有节点对应的线程
//node被取消了,但是cowait链表中的节点还是有效的,将其唤醒后,他们会重新插入到同步链表中等待被唤醒
for (WNode r = group.cowait; r != null; r = r.cowait) {
if ((w = r.thread) != null)
U.unpark(w); // wake up uncancelled co-waiters
}
for (WNode pred = node.prev; pred != null; ) { // unsplice
WNode succ, pp; // find valid successor
//如果node的下一个节点为null或者状态是CANCELLED
//如果node的下一个节点不是CANCELLED就不会进入while循环
while ((succ = node.next) == null ||
succ.status == CANCELLED) {
WNode q = null; // find successor the slow way
//从wtail往前遍历找到node后的第一个不是CANCELLED的节点
for (WNode t = wtail; t != null && t != node; t = t.prev)
if (t.status != CANCELLED)
q = t; // don't link if succ cancelled
if (succ == q || //succ和q都是null
//succ和q不等,说明succ和q都不是null,将node的next属性修改成q
U.compareAndSwapObject(node, WNEXT,
succ, succ = q)) {
if (succ == null && node == wtail) //如果node就是最后一个节点,将前一个节点作为WTAIL,退出while循环
U.compareAndSwapObject(this, WTAIL, node, pred);
break;
}
}
//上面while循环退出,succ要么为null,此时pred作为wtail,要么为一个非CANCELLED节点
//将pred的next属性修改为succ
if (pred.next == node) // unsplice pred link
U.compareAndSwapObject(pred, WNEXT, node, succ);
if (succ != null && (w = succ.thread) != null) {
//唤醒succ对应的线程
succ.thread = null;
U.unpark(w); // wake up succ to observe new pred
}
//如果前一个节点的状态不是CANCELLED则终止循环
if (pred.status != CANCELLED || (pp = pred.prev) == null)
break;
//前一个节点的状态是CANCELLED且pp非空
//将prev移除,pp的next指向succ
node.prev = pp; // repeat if new pred wrong/cancelled
U.compareAndSwapObject(pp, WNEXT, pred, succ);
pred = pp;
}
}
}//if结束
//node或者group有一个为空
WNode h; // Possibly release first waiter
while ((h = whead) != null) {
long s; WNode q; // similar to release() but check eligibility
//如果下一个节点为null或者是CANCELLED
if ((q = h.next) == null || q.status == CANCELLED) {
//从wtail往前遍历,找到h后的第一个status小于0的节点
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 && // waiter is eligible
(s == 0L || q.mode == RMODE))
release(h);
break;
}
}
return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
}
private void release(WNode h) {
if (h != null) {
WNode q; Thread w;
//将h的状态由WAITING改成0
U.compareAndSwapInt(h, WSTATUS, WAITING, 0);
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;
}
//唤醒q对应的线程
if (q != null && (w = q.thread) != null)
U.unpark(w);
}
}
public boolean tryLock() { return tryWriteLock() != 0L; }
public boolean tryLock(long time, TimeUnit unit)
throws InterruptedException {
return tryWriteLock(time, unit) != 0L;
}
public long tryWriteLock() {
long s, next;
//跟writeLock的实现一致,区别在于,如果条件不成立,tryWriteLock返回0,writeLock调用acquireWrite方法
return ((((s = state) & ABITS) == 0L &&
U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
next : 0L);
}
public long tryWriteLock(long time, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(time);
if (!Thread.interrupted()) {//如果线程未被中断
long next, deadline;
if ((next = tryWriteLock()) != 0L) //尝试获取锁成功
return next;
if (nanos <= 0L)
return 0L;
if ((deadline = System.nanoTime() + nanos) == 0L) //deadline超过允许的最大值了
deadline = 1L;//置为1
//通过acquireWrite获取锁,如果不是被中断的
if ((next = acquireWrite(true, deadline)) != INTERRUPTED)
return next;
}
//如果被中断则抛出异常
throw new InterruptedException();
}
因为StampedLock的写锁不支持重入,所以此处unlock没有检查state等于0,也没有将state减去WBIT,相反还加了一个WBIT,如果达到最大值了则将其恢复成初始值ORIGIN,即写锁是否被占用了不是通过state的值来判断的,而是通过WBIT对应的第8位的位,如果是1表示占有了写锁,如果是0则表示写锁被释放了。
public void unlock() { unstampedUnlockWrite(); }
final void unstampedUnlockWrite() {
WNode h; long s;
//如果未获取写锁则抛出异常
if (((s = state) & WBIT) == 0L)
throw new IllegalMonitorStateException();
//如果s达到最大值将恢复成初始值
state = (s += WBIT) == 0L ? ORIGIN : s;
//加入到链表后状态会变成WAITING
if ((h = whead) != null && h.status != 0)
//唤醒下一个节点
release(h);
}
private void release(WNode h) {
if (h != null) {
WNode q; Thread w;
//将状态从WAITING置为0
U.compareAndSwapInt(h, WSTATUS, WAITING, 0);
if ((q = h.next) == null || q.status == CANCELLED) {
//next为空或者状态是CANCELLED,从wtail往前遍历找到h后第一个状态为WAITING的节点
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);
}
}
unlockWrite是与writeLock、writeLockInterruptibly或者tryWriteLock 配合使用的,这三个方法返回成功加锁时的state属性值,unlockWrite据此解锁。tryUnlockWrite的实现和unstampedUnlockWrite类似,区别在于如果当前线程不持有写锁,前者返回false,后者抛出异常,如下:
public void unlockWrite(long stamp) {
WNode h;
//state变了或者求其等于0都说明当前线程未占有锁,则抛出异常
//占有锁时,因为写锁只能一个线程占有,所以state值是不变的
if (state != stamp || (stamp & WBIT) == 0L)
throw new IllegalMonitorStateException();
//如果stamp达到最大值了,则重置成ORIGIN初始值
state = (stamp += WBIT) == 0L ? ORIGIN : stamp;
if ((h = whead) != null && h.status != 0)
//唤醒下一个节点
release(h);
}
public boolean tryUnlockWrite() {
long s; WNode h;
if (((s = state) & WBIT) != 0L) {
//如果没有占有锁,返回false
//如果stamp达到最大值了,则重置成ORIGIN初始值
state = (s += WBIT) == 0L ? ORIGIN : s;
if ((h = whead) != null && h.status != 0)
//唤醒下一个节点
release(h);
return true;
}
return false;
}
获取读锁的过程中也加入了自旋等待的逻辑,如果当前只有一个节点,自旋等待该节点释放锁,自旋最多64次,同样的只有返回的随机数大于0才认为是一次有效自旋,否则继续内层的for循环,即实际的自旋等待次数最大不止64次。如果有多个节点或者自旋等待达到最大次数了whead节点未释放锁则往同步链表中添加一个新节点,同样的添加新节点逻辑被拆分成多个,每执行一部分逻辑就走外层for循环一遍,尝试抢占锁。注意如果wtail节点是写锁节点则在后面插入一个新的节点,如果是读锁节点,则在该节点的cowait链表中插入新节点。加入到cowait后线程会阻塞,再次唤醒时会检查之前的写锁是否被释放了,如果是则获取读锁。加入到同步链表后,会将状态改成WAITIN,然后被阻塞,再次唤醒时会检查是否被中断,检查当前是否只有一个节点了,如果只有一个则自旋等待最多1024次,同样的返回的随机数大于0才认为是一次有效自旋,否则继续内层的for循环,达到1024后还是一个节点,则将自旋等待的次数扩大一倍后继续自旋,直到达到最大值65536不再扩容,但是依然会自旋等待。
public void lock() { readLock(); }
public void lockInterruptibly() throws InterruptedException {
readLockInterruptibly();
}
public long readLock() {
long s = state, next; // bypass acquireRead on common uncontended case
return ((whead == wtail //说明没有等待的节点
&& (s & ABITS) < RFULL //读锁重入的次数小于最大值且此时写锁未被占有
&& U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ? //增加锁重入次数成功,即获取读锁成功,返回next
next : acquireRead(false, 0L));//获取读锁失败则调用acquireRead
}
public long readLockInterruptibly() throws InterruptedException {
long next;
if (!Thread.interrupted() && //线程没有被中断
(next = acquireRead(true, 0L)) != INTERRUPTED)
return next;
throw new InterruptedException();
}
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;;) {
if ((m = (s = state) & ABITS) < RFULL ? //读锁重入的次数小于最大值且此时写锁未被占有
//上述条件成立,则修改state,修改成功表示获取读锁成功
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
//上述条件不成立,如果w小于WBIT说明写锁没有被占用,此时还是读锁,但是读锁的重入次数达到最大值了
//tryIncReaderOverflow不等于0说明增加readerOverflow成功,则表示获取读锁成功,返回ns
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L))
return ns;
else if (m >= WBIT) {
//说明此时写锁被占有了
if (spins > 0) {
//如果生成的随机数大于0,将spins减1
if (LockSupport.nextSecondarySeed() >= 0)
--spins;
}
else {
if (spins == 0) {
//达到最大自旋次数,注意自旋是内层的for循环,自旋过程中h和p都是不改变的
WNode nh = whead, np = wtail;
if ((nh == h && np == p) //链表头和链表尾没有改变,即写锁未释放
|| (h = nh) != (p = np) //链表头和链表尾不一样了,即有新的等待节点
)
break;//终止for循环
}
//初始化spins
spins = SPINS;
}
}
}//for循环结束
}//if结束
//长时间写锁未释放或者有新的等待节点
//p就是wtail
if (p == null) { //初始化链表
WNode hd = new WNode(WMODE, null);
if (U.compareAndSwapObject(this, WHEAD, null, hd))
wtail = hd;
}
else if (node == null) //初始化node属性
node = new WNode(RMODE, p);
else if (h == p || p.mode != RMODE) {
//h等于p说明没有其他等待节点了
//p.mode != RMODE说明wtail节点是获取写锁的节点
if (node.prev != p)
node.prev = p;//设置prev属性
else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
//修改wtail为node,然后终止外层for循环,进入第二个大的for循环
p.next = node;
break;
}
}
//有其他的等待节点且wtail节点是获取读锁的节点
//将node的cowait赋值成p的cowait,将p的cowait属性修改为node,即把node加入到p的cowait链表中
//此时不在插入一个新节点
else if (!U.compareAndSwapObject(p, WCOWAIT,
node.cowait = p.cowait, node))
//如果修改失败,说明有线程在并发的获取读锁,将cowait置为null,通过外层for循环再次重试
node.cowait = null;
else {
//上述compareAndSwapObject修改成功,即node成功加入到p的cowait链表中,开始新的for循环,此时p是一个获取读锁的节点,p的前一个节点肯定是获取写锁的节点
for (;;) {
WNode pp, c; Thread w;
//借助for循环,将head节点上的cowait链表节点对应的线程都唤醒,唤醒后会自旋等待head节点释放锁
//如果head节点本身就是获取读锁的节点,则直接获取读锁
if ((h = whead) != null && (c = h.cowait) != null && //whead的cowait不为空
U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) && //将whead的cowait修改为c的cowait
(w = c.thread) != null) // help release
U.unpark(w); //唤醒whead的cowait对应的线程
if (h == (pp = p.prev) || h == p || pp == null) {
//h等于p说明之前的写锁节点已经释放了,当前head节点就是获取读锁的节点,通过下面的while循环获取读锁
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)) //达到最大次数了,增加readerOverflow属性
return ns;
} while (m < WBIT);
}
if (whead == h && p.prev == pp) {
//链表头和前一个节点未发生改变
long time;
if (pp == null || h == p || p.status > 0) {
//正常不会进入此分支
node = null; // throw away
break; //终止内层for循环
}
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;
if ((h != pp || (state & ABITS) == WBIT) && //当前写锁被占有了
whead == h && p.prev == pp) //链表头和p的前一个节点未改变
U.park(false, time); //将当前线程阻塞,当p节点变成链表头后会唤醒当前节点,然后走上一个if分支获取锁
//线程被唤醒
node.thread = null;
U.putObject(wt, PARKBLOCKER, null);
if (interruptible && Thread.interrupted()) //如果是被中断的
return cancelWaiter(node, p, true);
}
}//内层for循环结束
}
} //最外层的for循环结束
//当前面一个节点是写锁节点,然后插入了一个新的读锁节点后会跳出最外层循环,进入此逻辑
//此时p为上一个节点
for (int spins = -1;;) {
WNode h, np, pp; int ps;
if ((h = whead) == p) { //没有等待的节点了
if (spins < 0)
//初始化自旋次数
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) ://重入锁的次数没有到最大值,增加state属性
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) { //达到最大次数了,增加readerOverflow属性
//获取读锁成功
WNode c; Thread w;
whead = node;
node.prev = null;
//唤醒cowait链表中所有节点
while ((c = node.cowait) != null) {
//原子的修改node的cowait属性指向下一个cowait节点
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;
//还有其他的等待节点,唤醒head上cowait链表节点对应的线程,被唤醒后他们会自旋等待head节点的写锁释放
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; // stale
}
else if ((ps = p.status) == 0)
//将p的状态修改成WAITING
U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
else if (ps == CANCELLED) {
//将节点p移除
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的状态是WAITING
(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); //线程被中断,将该节点置为CANCELLED
}
}
}//for循环结束
}
private long tryIncReaderOverflow(long s) {
// assert (s & ABITS) >= RFULL;
if ((s & ABITS) == RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
//增加readerOverflow
++readerOverflow;
//恢复state
state = s;
return s;
}
}
else if ((LockSupport.nextSecondarySeed() &
OVERFLOW_YIELD_RATE) == 0)
Thread.yield();
return 0L;
}
public boolean tryLock() { return tryReadLock() != 0L; }
public boolean tryLock(long time, TimeUnit unit)
throws InterruptedException {
return tryReadLock(time, unit) != 0L;
}
public long tryReadLock() {
for (;;) {
long s, m, next;
if ((m = (s = state) & ABITS) == WBIT)//如果写锁被占用了,返回0
return 0L;
else if (m < RFULL) {
//如果写锁未被占用,读锁重入次数未达到最大值,则修改state属性成功
if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
return next;
}
//读锁重入次数未达到最大值,增加readerOverflow成功
else if ((next = tryIncReaderOverflow(s)) != 0L)
return next;
}
}
public long tryReadLock(long time, TimeUnit unit)
throws InterruptedException {
long s, m, next, deadline;
long nanos = unit.toNanos(time);
if (!Thread.interrupted()) {
if ((m = (s = state) & ABITS) != WBIT) {
//同上,写锁未被占用
if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
return next;
}
else if ((next = tryIncReaderOverflow(s)) != 0L)
return next;
}
//尝试获取读锁失败或者写锁被占用了,通过acquireRead获取读锁
if (nanos <= 0L)
return 0L;
if ((deadline = System.nanoTime() + nanos) == 0L) //超过最大值了
deadline = 1L;
if ((next = acquireRead(true, deadline)) != INTERRUPTED)
return next;
}
throw new InterruptedException();
}
读锁支持锁重入,因此unlock需要检查锁重入的次数是否减到0了,如果state中保存的锁重入次数达到最大值了,则将readOverflow属性减1,否则将state中的锁重入次数减1,直到其变成0了,读锁释放,唤醒同步链表中的下一个节点。
public void unlock() { unstampedUnlockRead(); }
final void unstampedUnlockRead() {
for (;;) {
long s, m; WNode h;
//如果没有获取读锁或者写锁被占用了,则抛出异常
if ((m = (s = state) & ABITS) == 0L || m >= WBIT)
throw new IllegalMonitorStateException();
else if (m < RFULL) {
//如果没有达到最大次数,将state减1
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
//如果锁重入次数变成0了,则唤醒下一个节点对应的线程
release(h);
break;
}
}
else if (tryDecReaderOverflow(s) != 0L) //达到最大次数了,减少readerOverflow属性
break;
}
}
private long tryDecReaderOverflow(long s) {
// assert (s & ABITS) >= RFULL;
if ((s & ABITS) == RFULL) {
//正常情形会进入此分支
if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
int r; long next;
//将readerOverflow减1,state不变
if ((r = readerOverflow) > 0) {
readerOverflow = r - 1;
next = s;
}
else
//如果readerOverflow等于0了,则修改state属性
next = s - RUNIT;
state = next;
return next;
}
}
else if ((LockSupport.nextSecondarySeed() &
OVERFLOW_YIELD_RATE) == 0)
Thread.yield();
return 0L;
}
unlockRead与直接使用readLock、readLockInterruptibly或tryReadLock时配合使用,这三个方法返回加锁成功时的state值,unllockRead据此解锁;tryUnlockRead也是解锁,区别在于如果当前线程没有占有读锁,前者抛出异常,后者返回false,如下:
public void unlockRead(long stamp) {
long s, m; WNode h;
for (;;) {
//将state与SBITS求且,算出来的是加写锁的累计次数,如果两个不等说明加了写锁,因为读锁未释放时不能加写锁
//所以如果state和stamp求且的结果不等,说明当前线程未获取写锁,抛出异常
if (((s = state) & SBITS) != (stamp & SBITS) ||
(stamp & ABITS) == 0L //stamp下读锁和写锁都没有占有,stamp为非法值
|| (m = s & ABITS) == 0L //state下读锁和写锁都没有占有
|| 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)
//如果锁重入次数减到0了,表示读锁完全释放了,唤醒下一个节点
release(h);
break;
}
}
else if (tryDecReaderOverflow(s) != 0L)
//达到最大锁重入次数了,减少readerOverflow属性
break;
}
}
public boolean tryUnlockRead() {
long s, m; WNode h;
while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
//只有上述条件成立才是占有读锁
if (m < RFULL) {
//没有达到最大锁重入次数
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
//锁重入次数减一
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return true;
}
}
else if (tryDecReaderOverflow(s) != 0L) //达到最大锁重入次数了,减少readerOverflow属性
return true;
}
//没有占有读锁
return false;
}
乐观读锁的实现就是基于两个方法,tryOptimisticRead 和 validate,tryOptimisticRead会判断写锁是否被占用,如果是返回0,否则返回写锁被占用的累计次数;validate判断写锁被占用的累计次数是否改变,如果改变则说明写锁被占用了,不能获取读锁;否则没有被占用,可以获取读锁,其实现如下:
public long tryOptimisticRead() {
long s;
//如果没有加写锁,返回此时获取写锁的累计次数,否则返回0
return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
}
public boolean validate(long stamp) {
//内存屏障,让之前的写操作指令都回写到内存中
U.loadFence();
//判断写锁的累计次数是否发生改变,如果改变了,说明写锁被占用了,返回false,否则返回true
return (stamp & SBITS) == (state & SBITS);
}
三种锁都有对应的tryConvertTo方法,其实现如下:
public long tryConvertToWriteLock(long stamp) {
long a = stamp & ABITS, m, s, next;
//如果写锁的次数未发生改变,从stamp到现在未获取过写锁或者写锁一直没释放
while (((s = state) & SBITS) == (stamp & SBITS)) {
//如果是乐观读锁
if ((m = s & ABITS) == 0L) {
//stamp不是乐观读锁
if (a != 0L)
break;
if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
return next;
}
else if (m == WBIT) {//当前写锁被占用了
if (a != m) //stamp没有占用写锁
break;
//a等于m
return stamp;
}
else if (m == RUNIT && a != 0L) {//当前读锁被占用了,且只重入了一次,a不等于0,stamp也是读锁
//减去RUNIT表示释放读锁,加上WBIT表示获取写锁
if (U.compareAndSwapLong(this, STATE, s,
next = s - RUNIT + WBIT))
return next;
}
else
break;
}
return 0L;
}
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;
//a也是乐观读锁
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;
//a也是写锁,加WBIT是释放写锁,加RUNIT是获取读锁
state = next = s + (WBIT + RUNIT);
if ((h = whead) != null && h.status != 0)
//写锁释放,唤醒下一个节点,被唤醒后等待读锁释放
release(h);
return next;
}
else if (a != 0L && a < WBIT)
//本身占有读锁
return stamp;
else
break;
}
return 0L;
}
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) { //如果当前是乐观读锁,stamp也是乐观读锁
if (a != 0L)
break;
return s;
}
else if (m == WBIT) { //当前是写锁
if (a != m)
break;
//stamp也是写锁,将写锁释放
state = next = (s += WBIT) == 0L ? ORIGIN : s;
if ((h = whead) != null && h.status != 0)
//写锁释放,唤醒下一个节点
release(h);
return next;
}
//当前是读锁
else if (a == 0L || a >= WBIT) //stamp是乐观读锁或者写锁
break;
//stamp也是读锁
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;
}
unlock是配合锁转换使用的,通用的解锁方法,其实现如下:
public void unlock(long stamp) {
long a = stamp & ABITS, m, s; WNode h;
while (((s = state) & SBITS) == (stamp & SBITS)) {
if ((m = s & ABITS) == 0L)//乐观读锁,直接返回
break;
else if (m == WBIT) {//写锁被占用了
if (a != m)
break;
//a等于m,a也是写锁
//释放写锁
state = (s += WBIT) == 0L ? ORIGIN : s;
if ((h = whead) != null && h.status != 0)
//唤醒下一个节点
release(h);
return;
}
//当前是读锁,stamp是乐观锁或者写锁
else if (a == 0L || a >= WBIT)
break;
//当前是读锁,stamp是读锁
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;
}
//退出while循环抛出异常
throw new IllegalMonitorStateException();
}