关于JAVA中Lock中的条件队列方法的疑问。先上源码
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
/*
* If cannot change waitStatus, the node has been cancelled.
*/
if (!compareAndSetWaitStatus(node, 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 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) // 这里有疑问?
LockSupport.unpark(node.thread);
return true;
}
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) // 这里有疑问?
LockSupport.unpark(node.thread);
这两行代码是我有疑惑的地方。按照我的理解,ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)这个条件判断前驱节点是否是被取消,如果被取消,作者害怕我们转移到同步队列尾部的节点无法被正常唤醒,所以做了一步unpark操作。但是这里不会出现并发问题吗?或者说因为unpark的原因重新竞争锁,竞争失败的情况下,加入了一个重复的竞争节点到同步队列尾部?
不会。首先,你回想下。你进入signal方法的时候,你就已经 lock.lock 。你忘记了吗?你已经拿锁了