当前位置: 首页 > news >正文

java并发多线程显式锁Condition条件简介分析与监视器 多线程下篇(四)

Lock接口提供了方法Condition newCondition();用于获取对应锁的条件,可以在这个条件对象上调用监视器方法
可以理解为,原本借助于synchronized关键字以及锁对象,配备了一个监视器
而显式锁Lock与Condition则针对于一个锁对象,提供了多个监视器
尽管是提供了多个监视器,但是需要记住,是Lock接口提供方法才能够获取到条件对象,所以这些条件对象仍旧是绑定到某一把锁上的
我相信,只要理解了监视器的概念,对于Condition理解起来是不会存在任何难度的,因为本身就是另外一种实现方式
image_5c81c4bd_31bc
从下图可以直观的感受到Condition是作为Object监视器方法的另外实现
wait在这边叫做await
notify在这边叫做signal
image_5c81c4bd_1aeb

等待

await

在监视器上等待
void await() throws InterruptedException;   ,看得出来,此方法是支持中断的
除非发生以下事件,否则将会持续等待
  • 其他某个线程调用此 Condition 的 signal() 方法,并且碰巧唤醒的是该线程
  • 其他某个线程调用此 Condition 的 signalAll() 方法;
  • 其他某个线程中断当前线程
  • “虚假唤醒” 

awaitUninterruptibly

不支持中断的await方法,void awaitUninterruptibly();
从await()的介绍中看得出来,除非发生提到的四种情况,否则将会是等待状态
而void awaitUninterruptibly();则是await()的不可中断版本,也就是只会有三种情况会跳出等待
  • 其他某个线程调用此 Condition 的 signal() 方法,并且碰巧唤醒的是该线程
  • 其他某个线程调用此 Condition 的 signalAll() 方法;
  • 其他某个线程中断当前线程
  • “虚假唤醒”  

awaitNanos

    long awaitNanos(long nanosTimeout) throws InterruptedException;
支持设置超时的等待,参数为等待的纳秒的long型数值
他在基于await的前提下,新增加了超时跳出,否则将会一直等待,他的跳出条件如下
  • 其他某个线程调用此 Condition 的 signal() 方法,并且碰巧唤醒的是该线程
  • 其他某个线程调用此 Condition 的 signalAll() 方法;
  • 其他某个线程中断当前线程
  • “虚假唤醒”  
  • 已超过指定的等待时间新增
返回值
需要注意的是此方法的返回值,是一个long
我们设置了一个超时时间,那么到底用了多少秒,还剩下多少秒?这个返回值就是这意思:
(nanosTimeout - 实际花费时间)的估算值,如果小于等于0,表示没有剩余时长;如果大于0,可以用来确定如果等待返回了是否还需要继续等待?
比如,你在等朋友A,A说你等我一小时,于是你去睡觉了,结果你睡了半小时就被叫醒了,那么跟你本来要等的时间还差半小时
那还要不要继续等了?还是一定要等到总共一小时呢?
典型用法(来自API):
boolean aMethod(long timeout, TimeUnit unit) {
long nanos = unit.toNanos(timeout);
lock.lock();
try {
while (!conditionBeingWaitedFor()) {
if (nanos <= 0L)
return false;
nanos = theCondition.awaitNanos(nanos);
}
// ...
} finally {
lock.unlock();
}
}
上面的方法中,如果条件仍旧不满足,但是等待结束了(也就是等待了足够多的时间了),直接返回false;否则将会继续执行,直到等到最后一刻
ps:这种代码风格也就JDK常写,否者这种if形式,估计要被项目经理骂

await(long time, TimeUnit unit)

    boolean await(long time, TimeUnit unit) throws InterruptedException;
此方法也是设置超时时长的等待方法,第一个参数为时长个数,第二个参数为第一个参数的单位
他相当于awaitNanos方法的封装(此处是逻辑上看起来,而不是说就是这个方法的封装)
awaitNanos(unit.toNanos(time)) > 0
所以返回类型为boolean,显然true表示没有等待足够的时间;,false 表示等待了足够时间,也就是等待超时

awaitUntil

    boolean awaitUntil(Date deadline) throws InterruptedException;
awaitUntil类似于await(long time, TimeUnit unit),只不过不是设置超时时长,而是设置截止日期
逻辑上可以把他们理解为一回事,如果没有等待足够时长,那么返回true;如果等待超时那么返回false
常用的逻辑(来自API)
boolean aMethod(Date deadline) {
boolean stillWaiting = true;
lock.lock();
try {
while (!conditionBeingWaitedFor()) {
if (!stillWaiting)
return false;
stillWaiting = theCondition.awaitUntil(deadline);
}
// ...
} finally {
lock.unlock();
}
}
上面的代码中,如果等待了足够的时长(等待超时),那么就会返回false;如果还有剩余时间,继续等待
 
普通的await()方法和awaitUninterruptibly都是直白的等待,一个支持中断,一个不支持中断
有超时设置的三个方法:
awaitNanos、await(long time, TimeUnit unit)、awaitUntil
都是在await()的基础上对超时时长或者截止日期的设置使用
不过这几个方法会返回剩余的超时时长或者使用boolean指示是否还有剩余
所以如果条件不满足,如果还没等够时间,可以控制继续等待或者退出
而对于Object提供的wait方法,就不能做到这么灵活的控制,要么就条件不满足继续等待,要么醒来后继续做别的事情,没办法相对准确的控制“必须要等待一定的时长”,因为如果wait(一小时),5分钟后,被唤醒了,这个用掉了的五分钟(或者说还剩余55分钟,是不知道的)

唤醒

关于唤醒有与Object提供的类似的两个方法,他们的逻辑含义也是一样的,唤醒一个或者唤醒所有,概念上并没有太多需要注意的事情
void signal();
void signalAll();

总结

Condition本身就是Object中监视器概念的另外实现,所以监视器方法调用,也需要持有锁,也就是说:
调用Condition的await()和signal()等方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用
await系列方法相对于Object提供了更加灵活的使用形式,signal和signalAll的逻辑含义可以认为完全一致
另外需要注意await方法与Object中的wait一样,都会释放当前持有的锁,所以醒来之后,会需要重新获取锁
原文地址:java并发多线程显式锁Condition条件简介分析与监视器 多线程下篇(四)

转载于:https://www.cnblogs.com/noteless/p/10493944.html

相关文章:

  • 2019阿里云峰会-边缘计算专场,邀您共话大连接低时延场景下的技术探索与实践...
  • RPM 包的构建 - 实例
  • macOS Mojave 无法运行未签名程序的解决方案
  • js常见算法题
  • Jenkins控制台显示乱码
  • 代码整洁之道-第9章-单元测试-读书笔记
  • 系列教程丨用 Docker 探索开源软件 —— PostgreSQL(二)
  • 生成随机验证码
  • 云越发展,锁定问题就会越严重?
  • 4.14Python数据处理篇之Matplotlib系列(十四)---动态图的绘制
  • componentOptions配置选项的作用和用法
  • 技本功丨收藏!斜杠青年与你共探微信小程序云开发(下篇)
  • 什么样人适合学平面设计?零门槛入门工具收藏
  • Luogu P4011 孤岛营救问题
  • 程序员修仙之路--突破内存限制的高性能排序
  • 30天自制操作系统-2
  • CentOS 7 修改主机名
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • iOS小技巧之UIImagePickerController实现头像选择
  • leetcode46 Permutation 排列组合
  • Python语法速览与机器学习开发环境搭建
  • Spring Cloud Feign的两种使用姿势
  • Vue.js源码(2):初探List Rendering
  • 欢迎参加第二届中国游戏开发者大会
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 理清楚Vue的结构
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 用Visual Studio开发以太坊智能合约
  • 扩展资源服务器解决oauth2 性能瓶颈
  • !!Dom4j 学习笔记
  • #HarmonyOS:基础语法
  • #ifdef 的技巧用法
  • #数学建模# 线性规划问题的Matlab求解
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • (09)Hive——CTE 公共表达式
  • (day6) 319. 灯泡开关
  • (TipsTricks)用客户端模板精简JavaScript代码
  • (八)Flask之app.route装饰器函数的参数
  • (动态规划)5. 最长回文子串 java解决
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (南京观海微电子)——I3C协议介绍
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • .jks文件(JAVA KeyStore)
  • .NET Core 版本不支持的问题
  • .Net程序帮助文档制作
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • [AI]文心一言出圈的同时,NLP处理下的ChatGPT-4.5最新资讯
  • [AIGC] Nacos:一个简单 yet powerful 的配置中心和服务注册中心
  • [DAU-FI Net开源 | Dual Attention UNet+特征融合+Sobel和Canny等算子解决语义分割痛点]
  • [EFI]英特尔 冥王峡谷 NUC8i7HVK 电脑 Hackintosh 黑苹果efi引导文件
  • [HTML]Web前端开发技术28(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页
  • [IDF]啥?
  • [JDK工具-2] javap 类文件解析工具-帮助理解class文件,了解Java编译器机制
  • [Linux打怪升级之路]-信号的保存和递达
  • [mysql]游标和触发器