AQS源码解析(9)Condition.signal

2021-01-12  本文已影响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;
上一篇下一篇

猜你喜欢

热点阅读