Condition 源码解析

Condition 源码解析

文章目录

  • Condition 源码解析
    • 一、Condition
    • 二、Condition 源码解读
      • 2.1. lock.newCondition() 获取 Condition 对象
      • 2.2. condition.await() 阻塞过程
      • 2.3. condition.signal() 唤醒过程
      • 2.4. condition.await() 被唤醒后
    • 三、总结

一、Condition

在并发情况下进行线程间的协调,如果是使用的 synchronized 锁,我们可以使用 wait()/notify() 进行唤醒,如果是使用的 Lock 锁的方式,则可以使用 Condition 进行针对性的阻塞和唤醒,相较于 wait()/notify() 使用起来更灵活。那么 Condition 是如何实现线程的等待和唤醒的呢,本文通过解析Condition 的源码进行理解。

在进行源码分析前,先通过一个案例看下 Condition 是如何使用的

public class Test {public synchronized static void main(String[] args) throws InterruptedException {Lock lock = new ReentrantLock();Condition condition = lock.newCondition();new Thread(() -> {lock.lock();System.out.println("线程1开始等待!");try {condition.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程1被唤醒继续执行结束!");lock.unlock();}, "1").start();new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}lock.lock();System.out.println("开始唤醒线程!");condition.signal();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程2执行结束!");lock.unlock();}, "2").start();}
}

运行之后,可以看到下面日志:
在这里插入图片描述

由于在第一个线程中,使用的 condition.await() 因此当前线程会被阻塞挂起,而第二个线程,在 1s 后进行了 condition.signal() 操作,因此第一个线程会被唤醒继续执行。这里可以发现,第一个线程阻塞时锁并没有释放,而第二个线程在1s后也成功拿到锁了,所以表明在 condition.await() 时会自动释放当前锁,这点和 wait() 相同,在第二个线程进行了 condition.signal() 操作,第一个线程并没有继续向下执行,而是等待第二个线程处理完才会继续执行,由此可以表明被唤醒的线程会重新获取锁,成功获取锁后继续执行。

下面通过源码看下 Condition 是如何实现的等待唤醒。

二、Condition 源码解读

2.1. lock.newCondition() 获取 Condition 对象

首先看下在使用 lock.newCondition() 获取一个Condition 对象时,具体做了什么,这里以 ReentrantLock 为例,进入到 ReentrantLocknewCondition() 方法中,又执行了 SyncnewCondition() 方法,再进去就会发现其实是 new 了一个 ConditionObject 类对象:
在这里插入图片描述

下面点到这个类中,可以看到其实是 AQS 下的一个子类:
在这里插入图片描述

2.2. condition.await() 阻塞过程

了解到 Condition 的对象后,可以看到是 AQS 下的一个子类,那下面其他的方法也肯定依赖于 AQS ,下面看下 condition.await() 方法,点到 await() 方法中:

在这里插入图片描述

其中 addConditionWaiter() 则是将自己加入到 AQS的队列中,并获取到当前线程所在的 Node ,这里注意下 Node 的状态是 Node.CONDITION 也就是 -2,后面会依赖于该状态。

在这里插入图片描述在这里插入图片描述

再回到 await() 方法继续向下看,接着使用了 fullyRelease() 方法传入了当前的 Node ,这里的 fullyRelease() 方法主要做了释放当前线程锁的操作,可以看到又调用了 AQSrelease() 进行释放资源,也就是释放了当前所持有的锁。
在这里插入图片描述

回到 await() 方法中,当释放锁后,下面进入到了 while 循环中,通过查看 isOnSyncQueue() 方法,可以看到是符合while的条件也就可以进入到循环中:
在这里插入图片描述
在这里插入图片描述

在循环中可以明显的看到 LockSupport.park(this) ,将当前线程进行了阻塞。

2.3. condition.signal() 唤醒过程

上面已经看到线程被阻塞了,如果需要被唤醒则需要通过condition.signal(),这个方法是如何唤醒的呢?

下面来到 AbstractQueuedSynchronizer 类的 signal() 方法中:
在这里插入图片描述

主要执行了 doSignal() 方法,再点到 doSignal() 中,可以看到这里开启了一个循环,对链表的每一个元素都进行了 transferForSignal() 操作,这里也比较好理解,就是要唤醒等待中的线程。

在这里插入图片描述

下面点到 transferForSignal() 中,看下对每个 Node 都做了什么操作。点进去之后也比较好理解,如果状态是 Node.CONDITION 也就是 -2,刚才在解读 await() 方法时就提到这个状态了,这里正好形成了呼应,下面有个非常显眼的操作 LockSupport.unpark(node.thread) 直接唤醒了目标线程。也就是唤醒了 2.2 中的最后一步操作。

在这里插入图片描述

2.4. condition.await() 被唤醒后

await() 方法中的 LockSupport.park(this) 被唤醒后,继续向下执行,下面会判断下当前线程有没有被打断,如果没被打断则 break 终止循环继续执行。
在这里插入图片描述
在这里插入图片描述

下面会使用 AQSacquireQueued() 方法,将先进入队列的线程进行抢占锁资源,如果成功获取锁后就会继续执行,如果抢占失败则继续被挂起阻塞。

在这里插入图片描述
在这里插入图片描述

三、总结

通过上面的源码分析,应该对 Condition 有了新的理解和掌握,在源码中好多地方都使用了 CAS ,因此当竞争资源非常激烈时, Lock 的性能要远远优于 synchronized

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/184419.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【网络奇遇之旅】:那年我与计算机网络的初相遇

🎥 屿小夏 : 个人主页 🔥个人专栏 : 计算机网络 🌄 莫道桑榆晚,为霞尚满天! 文章目录 一. 前言二. 计算机网络的定义三. 计算机网络的功能3.1 资源共享3.2 通信功能3.3 其他功能 四. 计算机网络…

基于APM(PIX)飞控和missionplanner制作遥控无人车-从零搭建自主pix无人车无人履带车坦克-2(以乐迪crossflight飞控为例)

这里重点以乐迪crossflight飞控为例进行组装调试。 1.刷写固件 安装最新版的乐迪地面站,在官网可以下载。由于产品里面不好找到对应的飞控,可以在首页滑动图片里进入。 1.连接飞控和电脑,查看com口,安装驱动。 2.刷写固件。如果…

Web实现悬浮球-可点击拖拽禁止区域

这次要实现的是这种效果,能够在页面上推拽和点击的,拖拽的话,就跟随鼠标移动,点击的话,就触发新的行为,当然也有指定某些区域不能拖拽,接下来就一起来看看有什么难点吧~ 需要监听的鼠标事件 既…

理解DALL-E 2

1.简介 DALL-E 2的效果想必大家都已经很清楚了,效果是非常惊人的,该篇文章就是讲一下DALL-E 2的原理是什么。 2.方法 DALL-E 2的原理不难理解,前提是你知道CLIP。简单来说,CLIP是一个由文本和图片多模态训练的一个zero-shot模型…

IDEA专栏—重装IDEA的配置

文章目录 1、maven路径2、默认文件路径3、插件4、导包顺序5、快捷键6、调整配置插件 1、maven路径 2、默认文件路径 3、插件 4、导包顺序 import static all other imports <blank line> import java.* import javax.* <blank line> import all other imports <…

python实现获取aws route53域名信息

最近由于工作原因接触到aws的服务&#xff0c;我需要实时获取所有的域名信息&#xff0c;用于对其进行扫描&#xff0c;因此写了一个自动化爬取脚本 给需要的人分享。 1.基础准备 代码环境&#xff1a;python3 第三方库&#xff1a;boto3 &#xff08;安装方法pip install…

虚幻学习笔记7—蓝图接口

一、前言 蓝图接口就是可以在蓝图中实现的接口&#xff0c;有它方便的地方&#xff0c;可以很方便的调用到实现了接口的函数。 二、实现 2.1、创建一个蓝图接口 1&#xff09;可以添加多个函数。 2&#xff09;函数在蓝图接口中只能规定输入和输出参数。 只有输入参数的可以…

SSM校园学习助手系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 校园学习助手系统是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模…

C语言--每日选择题--Day30

第一题 1. i 5&#xff0c;j 7&#xff0c;i | j 等于多少&#xff1f; A&#xff1a;1 B&#xff1a;3 C&#xff1a;5 D&#xff1a;7 答案及解析 D &#xff5c;这个是按位或运算符&#xff0c;两个数的二进制位&#xff0c;有1为1&#xff0c;同0为0&#xff1b; i的二进…

ubuntu下训练自己的yolov5数据集

参考文档 yolov5-github yolov5-github-训练文档 csdn训练博客 一、配置环境 1.1 安装依赖包 前往清华源官方地址 选择适合自己的版本替换自己的源 # 备份源文件 sudo cp /etc/apt/sources.list /etc/apt/sources.list_bak # 修改源文件 # 更新 sudo apt update &&a…

虚拟机VMware下CentOS7.9对磁盘扩容

首先是在VMware虚拟下对机器进行关机&#xff0c;然后扩容后启动机器&#xff08;操作简单&#xff0c;忽略&#xff0c;网上很多&#xff09; 开始增加磁盘空间 查看磁盘空间 发现此时磁盘空间仍然没变化 df -lh 查看当前磁盘分区信息 fdisk -l 对新加磁盘空间进行分区操…

UG\NX二次开发 创建对象属性UF_ATTR_assign

文章作者:里海 来源网站:里海NX二次开发3000例专栏 感谢粉丝订阅 感谢 weixin_43890371 订阅本专栏,非常感谢。 简介 创建对象属性UF_ATTR_assign 这个函数在后续NX版本中被UF_ATTR_set_user_attribute替代,新的函数使用例子请参阅这篇文章《UG\NX二次开发 创建对象属性UF_…

UG\NX二次开发 获取对象上属性的锁定状态UF_ATTR_ask_locked

文章作者&#xff1a;里海 来源网站&#xff1a;里海NX二次开发3000例专栏 感谢粉丝订阅 感谢 2301_80435318 开发 订阅本专栏&#xff0c;非常感谢。 简介 设置对象上属性的锁定状态UF_ATTR_set_locked&#xff0c;需要先在“用户默认设置”中勾选“通过NX Open锁定属性”&…

shiro-cas处理请求的流程

1.shiro框架处理请求&#xff0c;首先会先经过AccessControlFilter的onPreHandle方法。 2.onPreHandle中 ①isAccessAllowed&#xff1a;判断用户是否登录 在登录的情况下会走此方法&#xff0c;此方法返回true直接访问控制器&#xff1b; ②onAccessDenied&#xff1a;是否是拒…

如何保证缓存和数据库的双写一致性?

一、什么是数据库和缓存双写一致性&#xff1f; 在分布式系统中&#xff0c;数据库和缓存会搭配一起使用&#xff0c;以此来保证程序的整体查询性能。也就说&#xff0c;分布式系统为了缓解数据库查询的压力&#xff0c;会将查出来的数据保存在缓存中&#xff0c;下次再查询时…

什么是UTM投影坐标系?​

UTM&#xff08;Universal Transverse Mercator Grid System&#xff0c;通用横墨卡托格网系统&#xff09;坐标是一种平面直角坐标。 这种坐标格网系统及其所依据的投影已经广泛用于地形图&#xff0c;作为卫星影像和自然资源数据库的参考格网以及要求精确定位的其他应用。 …

android framework分屏“官方”黑屏bug问题发现,你会分析吗?-千里马实战作业挑战

背景 hi&#xff0c;粉丝朋友们&#xff1a; 大家都知道马哥课程以实战为特色&#xff0c;这里的实战就是最贴近公司里面开发的实战项目。这些实战主要来自哪呢&#xff1f; 1、以前在公司的工作积累&#xff0c;自己在公司做过什么&#xff0c;这部分比较好毕竟都是搞过的 2…

webshell之API免杀

ScriptEngineManager命令执行免杀 ScriptEngineManager执行js代码 利用ScriptEngineManager可以执行js命令&#xff0c;但是由于一般情况下&#xff0c;即便能运行js代码也不一定能执行系统命令。因为一般情况下js执行系统命令主要是依靠两种方式&#xff0c;IE的ActiveX插件…

用纯 CSS 实现网格背景

是不是在日常开发中经常遇到实现网格的需求&#xff0c;网格通常对网页中展示的元素能起到很好的定位和对齐作用。 这里介绍如何只通过 CSS 来实现这个需求&#xff1f; 使用背景图 这里我们的背景图使用 SVG 来创建&#xff0c;首先&#xff0c;创建绘出一个正方形&#xff0c…

PC模糊搜索

双向绑定input输入框&#xff0c;监听值改变事件 <el-inputinput"input"v-model"queryParams.keyword"style"margin-bottom: 10px"type"text"prefix-icon"el-icon-search"size"small"placeholder"输入员工…