当我阅读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.
那么,我说的对吗?或者你可以告诉我为什么?谢谢您的回答。