Condition 原理解析

流程

在这里插入图片描述

当调用wait 方法的时候从拿到一个最新创建的Node并加入 Condition 队列
唤醒AQS队列中的一个线程
判断node是否在aqs 队列上
如果不在的话将当前线程阻塞
当调用signal方法的时候会唤醒指定的线程 并添加当前节点到AQS队列

wait()

        public final void await() throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            //添加一个节点到Condition 队列中 如果没有则创建放到尾节点 尾插法  节点状态为 condtition
            Node node = addConditionWaiter();
            //释放当前的锁 得到锁的状态 并唤醒处于 aqs队列的一个线程
            long savedState = fullyRelease(node);
            int interruptMode = 0;
            //判断一个节点是否在aqs队列上
            while (!isOnSyncQueue(node)) {
                //如果在 park自己阻塞等待
                LockSupport.park(this);
                 //判断自己是否被中断
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
             //尝试获取锁
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
             //如果node 的下一个节点不是null  清理condition队列上的节点
            if (node.nextWaiter != null) // clean up if cancelled
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                //线程中断抛异常
                reportInterruptAfterWait(interruptMode);
        }

创建Node 节点并加入Condition队列中(单向链表)

如果node 是空则创建一个新的node状态为 CONDITION并设置成尾节点
如果不是空并且节点状态不是 CONDITION 则从链表中删除 然后直接返回尾节点
如果不是空节点并且节点状态是 CONDITION 则把尾节点的下一个节点设置成刚构建好的节点

   private Node addConditionWaiter() {
            //拿到尾节点
            Node t = lastWaiter;
            // If lastWaiter is cancelled, clean out.
            //如果尾节点不等于空 并且尾节点的状态不是  CONDITION
            if (t != null && t.waitStatus != Node.CONDITION) {
                unlinkCancelledWaiters();
                t = lastWaiter;
            }
            //构建一个节点 节点状态为 CONDITION
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            if (t == null)
                //如果尾节点== null 把构建的节点设置成尾节点
                firstWaiter = node;
            else
                //否则把前一个节点的next指针指向构建的节点
                t.nextWaiter = node;
            //把刚构建的节点设置成尾节点
            lastWaiter = node;
            return node;
        }

删除不是CONDITION状态的节点

 private void unlinkCancelledWaiters() {
            Node t = firstWaiter;
            Node trail = null;
            // 如果首节点不为空
            while (t != null) {
            	// 获取到下个节点
                Node next = t.nextWaiter;
                // 如果该节点的状态不等于conditon,则该节点需要在链表中删除
                if (t.waitStatus != Node.CONDITION) {
                	// 该节点的下个节点设置为空,意味着垃圾回收后就回收该节点
                    t.nextWaiter = null;
                    // trail 为空,则把下一个节点负责给首节点
                    if (trail == null)
                        firstWaiter = next;
                    else
                    	// 把下一个节点赋值给next,这样链表就要继续连接起来
                        trail.nextWaiter = next;
                    if (next == null)
                        lastWaiter = trail;
                }
                // 等于condtion,把该节点赋值给尾节点
                else
                    trail = t;
                // 下个一个节点赋值给t,进行下一次循环
                t = next;
            }
        }

唤醒AQS队列中的一个线程

  final long fullyRelease(Node node) {
        boolean failed = true;
        try {
            //拿当前锁的状态值
            long savedState = getState();
              //释放锁
            if (release(savedState)) {
                failed = false;
                return savedState;
            } else {
                throw new IllegalMonitorStateException();
            }
        } finally {
            if (failed)
                node.waitStatus = Node.CANCELLED;
        }
    }
    protected final boolean tryRelease(int releases) {
            //state -1
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                 //如果c =0 表示当前是无锁状态 把线程iq清空
                free = true;
                setExclusiveOwnerThread(null);
            }
            //重新设置 state
            setState(c);
            return free;
        }
 private void unparkSuccessor(Node node) {
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
        int ws = node.waitStatus;
        if (ws < 0)
            //设置head节点的状态为0 
            compareAndSetWaitStatus(node, ws, 0);

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        //拿到head节点的下一个节点
        Node s = node.next;
        //如果下一个节点为null 或者 status>0则表示是 CANCELLED 状态
        //听过尾部节点开始扫描  找到距离 head最近的一个 waitStatus<=0的节点
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        //如果next 节点不等于空直接唤醒这个线程
        if (s != null)
            LockSupport.unpark(s.thread);
    }

判断当前节点是否在同步队列中,返回 false 表示不在,返回true 表示如果不在,将当前线程挂起

final boolean isOnSyncQueue(Node node) {
		// 如果状态是condition,证明一定不再同步队列里,condition状态只存在于等待队列,在同步队列里,node.prev是一定不为空的,因为有个head的节点
        if (node.waitStatus == Node.CONDITION || node.prev == null)
            return false;
        // 在等待队列里,node.next 是等于空的,不等于空就是在同步队列当中
        if (node.next != null) // If has successor, it must be on queue
            return true;
       // 遍历正个同步队列,判断node是否在同步队列当中
        return findNodeFromTail(node);
    }

比如由于线程A调用了await 方法然后进入阻塞状态并唤醒了处于aqs 队列中的线程B此时线程B执行调用 signal 会唤醒处于 Condition 队列中阻塞等待的节点

signal

public final void signal() {
	// 判断当前线程是否获取到了锁,如果没有抛异常
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            // 如果首节点不为空,唤醒首节点
            if (first != null)
                doSignal(first);
        }

doSignal

private void doSignal(Node first) {
            do {
            // frist的下一个节点如果为空,就把lastWaiter设置为空
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
             // 不为空,再把first 节点从等待队列中移除
                first.nextWaiter = null;
            } while (!transferForSignal(first) &&
            	// 返回false,firstWaiter已经被从新赋值过了,如果不是空,进行下一次遍历
                     (first = firstWaiter) != null);
        }

transferForSignal

final boolean transferForSignal(Node node) {
       // 如果该节点不是condition状态(可能编程了cancelled状态),waitStatus=0,就会设置失败,返回false
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;
	// 将该节点放入到AQS队列中
        Node p = enq(node);
        int ws = p.waitStatus;
        // 如果上一个节点状态没有被改变,也就是没有编程cancelled状态,就将该节点状态设置成singal状态
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
        // 如果状态已经是cancelled状态,将该节点的线程挂起
            LockSupport.unpark(node.thread);
        return true;
    }

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值