美文网首页
AQS源码解析(9)Condition.signal

AQS源码解析(9)Condition.signal

作者: 三斤牛肉 | 来源:发表于2021-01-12 14:32 被阅读0次

    signal和signalAll大同小异,本节我们来看下signal函数,signal核心调用的是doSignal,所以signal函数就不贴了:

    //doSignal只做了一件事,将wait队列中的节点移出道aqs的等待队列中
    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.
             *  看作者注解,如果不能将waitStatus设置成0,表示该节点是取消的,返回false
             *  这里有两种情况:
             *  1)ws的值不是condition(-2),说明已经被改变了
             *  2)cas失败,说明有另一个线程也同时在signal,
             *  不管哪种情况该node一定会被唤醒
             *  这里返回false,看上面函数的while进入循环,拿到下一个节点,继续
             */
            if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
                return false;
    
           //入aqs的等待队列
            Node p = enq(node);
            int ws = p.waitStatus;
            //ws>0说明不是正常等待状态(一般是cancel),可以看下面的源码注解
            //或者cas ws失败则唤醒node线程
            //注意这里的p是node的前置节点,假如cas成功,说明前置节点也是在等待状态,那么就不需要唤醒node线程(因为前置都在等待,node也一定是等待,等走aqs的正常流程唤醒就好了)
            //如果cas失败说明ws正在被其他线程修改,这里又有2种情况:
            //1)ws被修改成1(cancel),那么唤醒线程没问题
            //2)ws被修改成0,也就是p已经获得到锁,这样unpark后会让代码执行到acquireQueued()去cas尝试获取锁,以此来提高效率
            //再看如果ws<=0表示正常等待状态,不去唤醒线程会不会有问题?
            //那么线程会一直挂起直到被p唤醒,重新进入while (!isOnSyncQueue(node)) 这个时候一定在aqs的等待队列中,继续往下进入acquireQueued()去获取锁
            if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
                LockSupport.unpark(node.thread);
            return true;
        }
    
    /** waitStatus value to indicate thread has cancelled */
            static final int CANCELLED =  1;
            /** waitStatus value to indicate successor's thread needs unparking */
            static final int SIGNAL    = -1;
            /** waitStatus value to indicate thread is waiting on condition */
            static final int CONDITION = -2;
            /**
             * waitStatus value to indicate the next acquireShared should
             * unconditionally propagate
             */
            static final int PROPAGATE = -3;
    

    相关文章

      网友评论

          本文标题:AQS源码解析(9)Condition.signal

          本文链接:https://www.haomeiwen.com/subject/ujddaktx.html