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

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

Lock接口提供了方法Condition newCondition();用于获取对应锁的条件,可以在这个条件对象上调用监视器方法

可以理解为,原本借助于synchronized关键字以及锁对象,配备了一个监视器

而显式锁Lock与Condition则针对于一个锁对象,提供了多个监视器

尽管是提供了多个监视器,但是需要记住,是Lock接口提供方法才能够获取到条件对象,所以这些条件对象仍旧是绑定到某一把锁上的

我相信,只要理解了监视器的概念,对于Condition理解起来是不会存在任何难度的,因为本身就是另外一种实现方式

从下图可以直观的感受到Condition是作为Object监视器方法的另外实现

wait在这边叫做await

notify在这边叫做signal

等待

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一样,都会释放当前持有的锁,所以醒来之后,会需要重新获取锁

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 异常处理器详解 Java多线程异常处理机制 多线程中篇(四)

    你会发现,然而并没有什么卵用,主线程中的try catch并不会得到什么信息,跟原来的结果还是一样的,线程直接宕掉

    noteless
  • 线程概念简介 什么是线程 多线程上篇(七)

    在20世纪 60年代人们提出了进程的概念后,在OS中一直都是以进程作为能拥有资源和独立运行的基本单位的。

    noteless
  • Java线程Thread的状态解析以及状态转换分析 多线程中篇(七)

    在Thread类中有内部类 枚举State,用于抽象描述Java线程的状态,共有6种不同的状态

    noteless
  • [更新方法]关于Pychram/IDEA/等一系列全家桶最新版监听服务不能成功的问题解决方法

    简单、
  • pageadmin CMS网站制作教程:实例:如何制作一个报名表?

    pageadmin CMS网站建设教程:实例:如何制作一个报名表? 有时我们根据需求需要制作一些自定义表,该如何去制作呢?

    Almost Lover
  • CentOS7.X更新最新版本内核,解决BBR内核导致的无法编译安装!

    wget https://elrepo.org/linux/kernel/el7/x86_64/RPMS/kernel-ml-5.5.9-1.el7.elrep...

    Levi.Ackermann
  • Golang中make和new的区别

    func new(Type) *Type 接收一个参数,这个参数是一种类型,而不是一个值,分配好内存后,返回一个指向该类型内存地址的指针,这个指针指向的内容的...

    陶士涵
  • spring框架(2)— 面相切面编程AOP

    Mister24
  • AOP

    AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对...

    陈灬大灬海
  • CSS选择器知识点整理

    小胖

扫码关注云+社区

领取腾讯云代金券