如何理解AQS上的“unparkSuccessor”功能

时间:2016-12-18 12:49:53

标签: java concurrency

当我阅读Java关于AQS(AbstractQueuedSynchronizer)的消息来源时,我有一个疑问。

private void unparkSuccessor(Node node) {
    /*
     * If status is negative (i.e., possibly needing signal) try
     * to clear in anticipation of signalling.  It is OK if this
     * fails or if status is changed by waiting thread.
     */
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

    /*
     * Thread to unpark is held in successor, which is normally
     * just the next node.  But if cancelled or apparently null,
     * traverse backwards from tail to find the actual
     * non-cancelled successor.
     */
    Node s = node.next;
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        LockSupport.unpark(s.thread);
}

主要疑虑是:

if (s == null || s.waitStatus > 0) {
    s = null;
    for (Node t = tail; t != null && t != node; t = t.prev)
        if (t.waitStatus <= 0)
            s = t;
}

为什么如果取消或显然为空,从尾部向后移动以找到实际未取消的继承人?而不是从头部找到实际未取消的继任者? 谢谢你的回答。

1 个答案:

答案 0 :(得分:1)

这是一种保守的设计。在next方法中分配enq,设置新尾部并将先前尾部的next引用链接到新尾部不是原子操作。在for循环中,它首先分配prev字段,如果赢得compareAndSetTail,则在新尾节点旁边分配prev。 因此next路径是优化,如果next不为空并且next未取消,而不是向后遍历。

  

因此,查看null next字段并不一定意味着该节点位于队列末尾。   取消节点的下一个字段设置为指向节点本身而不是null,以使isOnSyncQueue的生活更轻松。

private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) { // Must initialize
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}