众所周知,AQS 通过调用releaseShared
来释放共享锁,而它会调用到doReleaseShared
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
而获得共享锁的线程,可能经过acquireShared(int arg) -> doAcquireShared(arg) -> 重复着阻塞和被唤醒(可能是这样) ->setHeadAndPropagate(node, r) -> doReleaseShared()
,而它也会调用到doReleaseShared
。
private void setHeadAndPropagate(Node node, int propagate) {
Node h = 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();
}
}
但获得共享锁的线程,是会判断 head 后继节点是否为共享锁节点的(if (s == null || s.isShared())
),才会去调用 doReleaseShared 。
但如果从释放共享锁的流程来看,根本不会判断 head 后继节点是否为共享锁节点的。然后就直接调动了 doReleaseShared:
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
当然,在 doReleaseShared 里,也不会在乎 head 后继是个啥,它都没有去看 head 后继是个啥。
所以,为什么 AQS 里共享锁的释放里,不需要判断 head 后继节点是不是共享锁节点?
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.