-
p不是头结点 or 获取锁失败,判断是否应该被阻塞
-
前继节点的ws = SIGNAL 时应该被阻塞
*/
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
(1)setHeadAndPropagate传播唤醒后继
自旋判断新节点node前驱是head,且尝试获取共享锁成功,则需要传播唤醒共享后继节点。基本流程如下:
-
node出队列,并成为新的head。
-
判断是否满足传播条件。
-
如若node还有后继且后继是共享节点,则执行唤醒操作
doReleaseShared。
(共享锁的传播模式比较复杂,如需深入了解,请阅读拙作《AQS源码解读(七)——从PROPAGATE和setHeadAndPropagate()分析共享锁的传播性》)
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
//设置node为新head
setHead(node);
//一连串判断满足后,唤醒共享后继
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
//唤醒后继共享节点
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}
(2)判断是否应该阻塞和阻塞线程
共享锁判断判断是否应该阻塞和阻塞线程的代码和独占锁的完全一样,不过多赘述。shouldParkAfterFailedAcquire主要做了如下几步:
-
判断node前驱状态是否为
SIGNAL,是则直接返回true。 -
node前驱状态不是
SIGNAL,有可能是ws>0,说明前驱取消了,自旋跳过取消的节点,并寻找链接一个正常的前驱。 -
node前驱状态不是
SIGNAL,有可能是0(初始化状态)或PROPAGATE(传播状态),修改node前驱状态为SIGNAL。
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
-
This node has already set status asking a release
-
to signal it, so it can safely park.
-
node拿锁失败,前继节点的状态是SIGNAL,node节点可以放心的阻塞,

最低0.47元/天 解锁文章
900

被折叠的 条评论
为什么被折叠?



