如何了解AQS上的“ isOnSyncQueue”功能

时间:2019-03-12 15:15:15

标签: java multithreading concurrency

当我阅读Java的有关AQS(AbstractQueuedSynchronizer)的资源时,我感到怀疑。

final boolean isOnSyncQueue(Node node) {
    if (node.waitStatus == Node.CONDITION || node.prev == null)
        return false;
    if (node.next != null) // If has successor, it must be on queue
        return true;
    /*
     * node.prev can be non-null, but not yet on queue because
     * the CAS to place it on queue can fail. So we have to
     * traverse from tail to make sure it actually made it.  It
     * will always be near the tail in calls to this method, and
     * unless the CAS failed (which is unlikely), it will be
     * there, so we hardly ever traverse much.
     */
    return findNodeFromTail(node);
}

主要的疑问是最后一条注释。当其他调用signal()方法的线程发出等待信号的条件线程时,其节点已排队进入同步队列。

final boolean transferForSignal(Node node) {
    /*
     * If cannot change waitStatus, the node has been cancelled.
     */
    if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
        return false;

    /*
     * Splice onto queue and try to set waitStatus of predecessor to
     * indicate that thread is (probably) waiting. If cancelled or
     * attempt to set waitStatus fails, wake up to resync (in which
     * case the waitStatus can be transiently and harmlessly wrong).
     */
    Node p = enq(node);
    int ws = p.waitStatus;
    if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
        LockSupport.unpark(node.thread);
    return true;
}

如果另一个线程没有完全执行enq(Node)方法,则该节点将一直尝试compareAndSetTail(oldTail, node)直到成功。执行完成后,该线程可能会发出信号。

我可以想象一种情况,当调用enq方法时,该线程是“惊喜唤醒”,并执行isOnSyncQueue方法。这时其waitStatus不是CONDITION,并且其prev设置为' enq',因此它可以满足注释中的内容。但是,由于节点CAS失败,当调用findNodeFromTail方法时,它不在同步队列中。findNodeFromTail没有意义。

enq调用成功并且上一个节点被取消时,它将释放该线程,但是该线程被意外唤醒,isOnSyncQueue方法返回false,并且该线程再次被阻塞。目前不会再发出信号。

if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
    LockSupport.unpark(node.thread);

下面是我说的(不允许浏览图片):

thread1: transferForSignal()  enq()
thread2: surprise wake up. execute isOnSyncQueue() and return fasle
thread1: enq() execute finish and prev is cancelled or CAS fail, 
         LockSupport.unpark(node.thread), this is make no sense.
thread2: LockSupport.park(this) and won't be signalled because 
         LockSupport.unpark(node.thread) has been invoked.

那么,我说的对吗?或者你可以告诉我为什么?谢谢您的回答。

0 个答案:

没有答案