ReentrantLock源码解析(二)----- 条件队列

直接看到aqs的ConditionObject类的await方法。

        public final void await() throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            //将当前线程包装为node,添加到条件队列中(现在节点是在条件等待队列中)
            Node node = addConditionWaiter();
            //释放锁资源(其他线程可以去抢锁了)
            int savedState = fullyRelease(node);
            int interruptMode = 0;
            //isOnSyncQueue判断该节点是否在同步等待队列(不是条件等待队列)中
            while (!isOnSyncQueue(node)) {
            	//休眠当前线程
                LockSupport.park(this);
                //是否被打断过,被打断过返回-1或者1,直接跳出循环
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            //当该node被signal进入同步等待队列中,之后被唤醒
            //或者该线程被打断醒来
            //执行下面代码
            //acquireQueued之前已经讲过了,这里会去获取锁,获取不到则休眠
            //如果获取到锁且返回true,说明在同步队列中获取锁时被打断过
            //且 如果 interruptMode 不为THROW_IE(不是在 条件等待队列中 被打断唤醒 进去同步队列的)
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
            	//interruptMode 设置为REINTERRUPT (1)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null) // clean up if cancelled
            	//清除被取消的节点
                unlinkCancelledWaiters();
            //被打断过
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
        }
        private void reportInterruptAfterWait(int interruptMode)
            throws InterruptedException {    
            if (interruptMode == THROW_IE)
                //抛出中断异常
                throw new InterruptedException();
            else if (interruptMode == REINTERRUPT)
            	//重新中断一次,设置中断标识,来标识曾经被中断过。
                selfInterrupt();
        }
        private Node addConditionWaiter() {
        	//获取到lastWaiter(队尾的等待节点),初始时为空
            Node t = lastWaiter;
            //如果lastWaiter不为空,且lastWaiter的waitStatus不为CONDITION ,说明lastWaiter被取消了
            if (t != null && t.waitStatus != Node.CONDITION) {
            	//将所有被取消的节点从等待队列中去除
                unlinkCancelledWaiters();
                //去除后,重新获取lastWaiter
                t = lastWaiter;
            }
            //将当前线程封装为node节点,waitStatus为CONDITION
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            //如果lastWaiter为空,队列中啥都没有
            if (t == null)
            	//设置firstWaiter(队头的等待节点)为node
                firstWaiter = node;
            //如果不为空,将lastWaiter的nextWaiter指向当前节点
            else
                t.nextWaiter = node;
            //node成为lastWaiter
            lastWaiter = node;
            return node;
        }
        private void unlinkCancelledWaiters() {
        	//获取firstWaiter
            Node t = firstWaiter;
            Node trail = null;
            //当t为空,退出循环
            while (t != null) {
            	//获取下一个节点
                Node next = t.nextWaiter;
                //如果当前节点被取消
                if (t.waitStatus != Node.CONDITION) {
                	//将当前节点的下一个节点置为空
                    t.nextWaiter = null;
                    //trail为空(还没找到未被取消的正常节点)
                    if (trail == null)
                    	//头结点被取消了,头结点置为下一个节点
                        firstWaiter = next;
                    //trail已经记录了正常等待的节点
                    else
                    	//使该正常等待的节点的下一个节点指向next
                        trail.nextWaiter = next;
                    //next为空(队列遍历完了)
                    if (next == null)
                    	//将lastWaiter置为trail
                        lastWaiter = trail;
                }
                //当前节点没被取消了
                else	
                	//trail记录着每次循环找到的正常等待节点
                    trail = t;
                //将t设置为下一个节点
                t = next;
            }
        }
    final int fullyRelease(Node node) {
        boolean failed = true;
        try {
        	//获取当前的state
            int savedState = getState();
            //release之前的文章已经讲过
            //释放锁,唤醒正常排队的线程(如果有的话)
            if (release(savedState)) {
                failed = false;
                return savedState;
            } else {
                throw new IllegalMonitorStateException();
            }
        } finally {
            if (failed)
            	//将node的waitStatus设置为CANCELLED
                node.waitStatus = Node.CANCELLED;
        }
    }
	final boolean isOnSyncQueue(Node node) {
		//如果当前节点的waitStatus为CONDITION,返回false
		//或者节点的前置节点为空(条件队列的节点的prev 和 next 属性为空)
        if (node.waitStatus == Node.CONDITION || node.prev == null)
            return false;
        //该节点的后置节点不为空
        if (node.next != null) // If has successor, it must be on queue
            return true;
        
        return findNodeFromTail(node);
    }
    private boolean findNodeFromTail(Node node) {
    	//获取同步等待队列的尾节点
        Node t = tail;
        //死循环
        for (;;) {
        	//同步等待队列中有该节点
            if (t == node)
                return true;
            //遍历完都没找到,则不在同步等待队列中
            if (t == null)
                return false;
            t = t.prev;
        }
    }
        private int checkInterruptWhileWaiting(Node node) {
        	//判断是否被打断过,并清除打断标志,被打断过则执行transferAfterCancelledWait
            return Thread.interrupted() ?
            	//transferAfterCancelledWait返回值:
            	//返回true,则说明节点是被打断唤醒放入同步等待队列而不是被signal放入同步等待队列,则返回THROW_IE (-1)
            	//返回false,说明节点已经被signal到同步等待队列,则返回REINTERRUPT (1)
                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
                //没有打断返回0
                0;
        }
        final boolean transferAfterCancelledWait(Node node) {
	        //cas设置该节点的状态为0
	        if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
	        	//cas设置成功,将node设置到同步等待队列的队尾
	        	//enq之前的文章已经说过了
	            enq(node);
	            //返回true
	            return true;
	        }
	        //cas失败,则说明该节点已经被signal了,要去进入同步等待队列了
	        //直到节点进入同步等待队列完毕前,该方法都不返回
	        while (!isOnSyncQueue(node))
	            Thread.yield();
	        //返回false
            return false;
   		}

直接看到aqs的ConditionObject类的signal方法和signalall方法。

        public final void signal() {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            //获取firstWaiter
            Node first = firstWaiter;
            if (first != null)
            	//唤醒节点
                doSignal(first);
        }
        private void doSignal(Node first) {
            do {
            	//first要被唤醒进入同步等待队列中,将firstWaiter设置为下一个节点
                if ( (firstWaiter = first.nextWaiter) == null)
                	//没有下一个节点了,将lastWaiter 置为空
                    lastWaiter = null;
                //将first的nextWaiter置为空
                first.nextWaiter = null;
            } while (!transferForSignal(first) &&
                     (first = firstWaiter) != null);
            //这里循环调用transferForSignal方法,如果first没有被取消,则调用完transferForSignal后,整个方法结束
            //如果first被取消,则执行(first = firstWaiter) != null),
            //被唤醒的节点被取消了则唤醒下一个节点,接着循环 , 如果没有下一个节点,则跳出循环。 
        }
        final boolean transferForSignal(Node node) {
	        //cas将node的WaitStatus设置为0
	        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
	        	//如果设置失败,说明waitstatus不为CONDITION ,节点只可能是被取消了。
	        	//返回false
	            return false;
	
	       	//将该节点设置到同步等待队列的队尾,
	       	//这里返回的p是该节点进入队尾后的前一个节点
	        Node p = enq(node);
	        int ws = p.waitStatus;
	        //如果p的waitStatus大于0,则说明p被取消了,没法再唤醒node了,所以这里直接唤醒node,让node去竞争锁
	        //如果p的waitStatus不大于0,cas将p的waitstatus改为SIGNAL,以后要去唤醒node
	        //cas设置p的waitstatus为SIGNAL失败,则直接唤醒node,让node去竞争锁
	        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
	            LockSupport.unpark(node.thread);
	        //node没有被取消,返回true
	        return true;
   		}
        public final void signalAll() {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            //获取firstWaiter
            Node first = firstWaiter;
            if (first != null)
           		//唤醒条件等待队列的所有节点
                doSignalAll(first);
        }
        private void doSignalAll(Node first) {
        	//要唤醒调节键队列的所有节点,所以将firstWaiter 和 lastWaiter 都置为空
            lastWaiter = firstWaiter = null;
            do {
            	//获取头结点的下一个节点
                Node next = first.nextWaiter;
                //将要唤醒的节点的nextWaiter 置空
                first.nextWaiter = null;
                //唤醒该节点,进入同步等待队列
                transferForSignal(first);
               	//first 设置为next 
                first = next;
            } while (first != null);
           //循环直到first的下一个节点为空
        }

到此。条件队列的等待和唤醒方法也就解析完了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值