流程

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

wait()

        public final void await() throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();//添加一个节点到Condition 队列中 如果没有则创建放到尾节点 尾插法  节点状态为 condtitionNode 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 cancelledunlinkCancelledWaiters();if (interruptMode != 0)//线程中断抛异常reportInterruptAfterWait(interruptMode);}

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

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

   private Node addConditionWaiter() {//拿到尾节点Node t = lastWaiter;// If lastWaiter is cancelled, clean out.//如果尾节点不等于空 并且尾节点的状态不是  CONDITIONif (t != null && t.waitStatus != Node.CONDITION) {unlinkCancelledWaiters();t = lastWaiter;}//构建一个节点 节点状态为 CONDITIONNode 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,把该节点赋值给尾节点elsetrail = 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 -1int c = getState() - releases;if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;if (c == 0) {//如果c =0 表示当前是无锁状态 把线程iq清空free = true;setExclusiveOwnerThread(null);}//重新设置 statesetState(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 queuereturn 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,就会设置失败,返回falseif (!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;}

Condition 原理解析相关推荐

  1. Python标准库threading模块Condition原理浅析

    Python标准库threading模块Condition原理浅析 本文环境python3.5.2 threading模块Condition的实现思路 在Python的多线程实现过程中,在Linux平 ...

  2. 002 第一季SpringBoot2核心技术-核心功能:配置文件、Web开发(原生组件)、数据访问、单元测试、指标监控、原理解析:@Value、命令行参数、手动获取bean、自定义starter

    三.核心技术之- ->核心功能 1. 配置文件 1.1 文件类型 1.1.1 properties 同以前的properties用法 优先级高于yml的方式. 1.1.2 yaml 1) 简介 ...

  3. JUC-Condition使用以及Condition原理分析

    1. 线程通信 ps:要想理解Condition原理,需要先了解AQS,不了解AQS的可以看先之前的文章->aqs源码解析 在Synchronized加锁状态时,是使用wait/notify/n ...

  4. Spark Shuffle原理解析

    Spark Shuffle原理解析 一:到底什么是Shuffle? Shuffle中文翻译为"洗牌",需要Shuffle的关键性原因是某种具有共同特征的数据需要最终汇聚到一个计算节 ...

  5. 秋色园QBlog技术原理解析:性能优化篇:用户和文章计数器方案(十七)

    2019独角兽企业重金招聘Python工程师标准>>> 上节概要: 上节 秋色园QBlog技术原理解析:性能优化篇:access的并发极限及分库分散并发方案(十六)  中, 介绍了 ...

  6. Tomcat 架构原理解析到架构设计借鉴

    ‍ 点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 Tomcat 架构原理解析到架构设计借鉴 Tomcat 发展这 ...

  7. 秋色园QBlog技术原理解析:性能优化篇:数据库文章表分表及分库减压方案(十五)...

    文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...

  8. CSS实现元素居中原理解析

    原文:CSS实现元素居中原理解析 在 CSS 中要设置元素水平垂直居中是一个非常常见的需求了.但就是这样一个从理论上来看似乎实现起来极其简单的,在实践中,它往往难住了很多人. 让元素水平居中相对比较简 ...

  9. 秋色园QBlog技术原理解析:Web之页面处理-内容填充(八)

    文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...

最新文章

  1. 测试适合眉形的软件_软件测试的自我修养:正向思维与逆向思维
  2. C++右值引用 和 std::move()
  3. Sql Server相关报错解决
  4. Asp.Net Mvc3.0(MEF依赖注入实例)
  5. 2.Lucene3.6.2包介绍,第一个Lucene案例介绍,查看索引信息的工具lukeall介绍,Luke查看的索引库内容,索引查找过程
  6. yolo opencv_如何使用Yolo,SORT和Opencv跟踪足球运动员。
  7. Android之不需要自定义View(ViewfindView.java)最简单的二维码扫描
  8. 微软计划Windows 7 SP2开发
  9. 21.docker logs
  10. 计算机应用论文投稿模板,标准期刊论文格式模板
  11. python种子数是什么意思_Python:随机种子问题
  12. 手机在我状态查询易语言代码
  13. 数字图像处理(4)——图像复原
  14. Android开发:toast封装工具类
  15. 连接重置Connection reset异常
  16. Android直播软件搭建左滑右滑清屏控件
  17. shiro中基于注解实现的权限认证过程
  18. 女孩子做项目管理的发展_我可以和孩子们一起做些有趣的技术项目吗?
  19. 自行車基本知識 (zz)
  20. Cookie在前端写还是后端?

热门文章

  1. 西安之行-兵马俑-大雁塔-古城墙
  2. JavaSE_day09【抽象类、多态、根父类】
  3. Java编程练习·编写USB接口模拟计算机启动与关闭
  4. 解析智能硬件“独角兽”们的发展态势!附2017年全球硬件领域“独角兽”企业榜单
  5. IDEA 自动生成实体类
  6. 关闭Microsoft Compatibility Telemetry服务解决VScode CPU内存占用过高导致电脑卡顿(实测有效)
  7. Oracle Indexes(索引)
  8. 淘宝升华:脱胎换骨的巨人
  9. VS2017目录结构-多项目开发 tcy
  10. 对某投票网站的刷票方式