ConditionObject.signal()方法的疑问

关于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的原因重新竞争锁,竞争失败的情况下,加入了一个重复的竞争节点到同步队列尾部?

阅读 2.2k
1 个回答
新手上路,请多包涵

不会。首先,你回想下。你进入signal方法的时候,你就已经 lock.lock 。你忘记了吗?你已经拿锁了

推荐问题