为什么 AQS 里共享锁的释放里,不需要判断 head 后继节点是不是共享锁节点?

2020-06-08 00:05:36 +08:00
 amiwrong123

众所周知,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 后继节点是不是共享锁节点?

1206 次点击
所在节点    Java
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/679531

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX