龙空技术网

“全栈2019”Java多线程第三十六章:如何设置等待线程的截止时间

人人都是程序员 219

前言:

而今姐妹们对“java 等待线程结束”大体比较注重,姐妹们都需要剖析一些“java 等待线程结束”的相关资讯。那么小编在网上汇集了一些有关“java 等待线程结束””的相关知识,希望大家能喜欢,姐妹们一起来了解一下吧!

难度

初级

学习时间

30分钟

适合人群

零基础

开发语言

Java

开发环境JDK v11IntelliJ IDEA v2018.3友情提示本教学属于系列教学,内容具有连贯性,本章使用到的内容之前教学中都有详细讲解。本章内容针对零基础或基础较差的同学比较友好,可能对于有基础的同学来说很简单,希望大家可以根据自己的实际情况选择继续看完或等待看下一篇文章。谢谢大家的谅解!1.温故知新

前面在《“全栈2019”Java多线程第三十三章:await与signal/signalAll》一章中介绍了Condition对象的await()方法与signal()/signalAll()方法。

在《“全栈2019”Java多线程第三十四章:超时自动唤醒被等待的线程》一章中介绍了Condition对象的await​(long time, TimeUnit unit)方法。

在《“全栈2019”Java多线程第三十五章:如何获取线程被等待的时间?》一章中介绍了Condition对象的awaitNanos​(long nanosTimeout)方法。

现在我们来讲解Condition对象的awaitUntil​(Date deadline)方法。

2.Object与Condition

实际上,当我们用显式锁Lock替代了synchronized时,Object的wait()、notify()和notifyAll()方法都被Condition对象中的方法所替代。

Object的wait()方法被Condition对象分解为以下几个方法:

void await()boolean await​(long time, TimeUnit unit)long awaitNanos​(long nanosTimeout)void awaitUninterruptibly()boolean awaitUntil​(Date deadline)

Object的notify()和notifyAll()方法被Condition对象分解为以下几个方法:

void signal()void signalAll()

以上几个方法后面几章都会讲解。

3.设置线程的等待截止时间awaitUntil​(Date deadline)方法

await()方法用在只需要使当前线程等待的场景;

await​(long time, TimeUnit unit)方法用在当线程等待超时时自动唤醒的场景,而且还可以判断出是人工唤醒还是自动唤醒,即当方法返回false时,是自动唤醒;当方法返回true时,是signal()/signalAll()方法唤醒。需要注意的是,中断线程并不会让程序正常往下执行,而是去执行catch或throws。

awaitNanos​(long nanosTimeout)方法用在当线程等待超时时自动唤醒的场景,而且还可以判断出是人工唤醒还是自动唤醒,即当方法返回大于等于0时,是自动唤醒;当方法返回值小于0时,是signal()/signalAll()方法唤醒。需要注意的是,中断线程并不会让程序正常往下执行,而是去执行catch或throws。

下面要为大家介绍一个等待家族的另一个方法:awaitUntil​(Date deadline)方法。

awaitUntil​(Date deadline)方法在Condition接口中的源码:

将注释翻译成中文:

中文注释全文:

造成当前线程在等待,直到它被唤醒,通常由被通知或中断或超过截止时间,自动唤醒。

去掉注释版:

awaitUntil​(Date deadline)方法造成当前线程在等待,直到它被唤醒,通常由被通知或中断或超过截止时间,自动唤醒。当被唤醒时,若已过截止时间返回false,否则返回true。

访问权限

boolean:awaitUntil​(Date deadline)方法返回boolean类型的值。当被唤醒时,若已过截止时间返回false,否则返回true。

awaitUntil​(Date deadline)方法只能被对象调用。

参数

Date deadline:等待的截止时间。

抛出的异常

throws InterruptedException:如果当前线程被中断(并且支持中断线程挂起)。

应用

我们可以看到awaitUntil​(Date deadline)方法又一个Date类型的参数deadline:

单词deadline翻译过来就是“最后期限”的意思。

这个参数的意思是让我们传递一个线程等待的截止时间。简单来讲,就是线程不再是等待多少秒了,而是截止到什么时候自动唤醒。

除了可以传递的参数以外,awaitUntil​(Date deadline)方法也会给我们一个返回值:

这个返回值类型是boolean类型,什么意思呢?

意思是:当被等待的线程唤醒时,如果此时线程等待时间没有超过截止时间就返回true,否则返回true。

“线程等待时间没有超过截止时间”说明什么?

说明线程不是因超时而自动唤醒的,而是调用Condition对象的signal()/signalAll()方法手动唤醒的。

换而言之,就是当我们调用Condition对象的signal()/signalAll()方法手动唤醒被等待线程时,awaitUntil​(Date deadline)方法返回true;当被等待线程因超时而自动唤醒时,awaitUntil​(Date deadline)方法返回false。

下面,我们就来试试awaitUntil​(Date deadline)方法。

首先,创建一个实现了Runnable接口的匿名内部类对象:

先不着急完善run()方法。

然后,创建出3个线程:

接着,启动线程:

再然后,我们来完善run()方法。

因为要使当前线程等待,所以需要持有锁和Condition对象。现在就将显式锁Lock和Condition都创建出来:

接着,在run()方法中写上同步:

然后,在获取锁之后调用Condition对象的awaitUntil​(Date deadline)方法使当前线程等待:

因为awaitUntil​(Date deadline)方法需要一个Date类型的参数,所以这里我们创建出一个Date类型的对象,调用Date.from()方法即可:

Date的from(Instant instant)方法需要一个Instant类型的参数,这里我们就调用Instant的now()方法得到当前时间:

得到当前时间还不行,我们还得延长5秒钟作为我们的截止时间。

为什么要延长5秒钟?

如果不延长5秒钟,那每次截止时间都是当前时间,次次都超时,如果把当前时间往后延长5秒钟作为截止时间的话,那么在截止时间到来之前我们都是来得及手动唤醒线程的。

我们可以调用Instant的plusSeconds()方法来延长时间,延长时间的单位是秒。这是大家调用此方法时需要注意的地方。

截止时间设置为5秒钟后:

因为awaitUntil​(Date deadline)方法会抛出异常,所以这里我们采用catch进行处理:

最后,我们在线程等待的前后各输出一句话:

例子书写完毕。

运行程序,执行结果:

从运行结果来看,符合预期。线程在5秒钟之后被自动唤醒。而且awaitUntil​(Date deadline)方法返回false,说明就是自动唤醒的。

4.截止时间是未来的1分钟、1小时、1天、1周、1个月、1年,怎么写?

这里呢,我们就不写在上一小节的例子最中了,代码单独列出来,大家要用时随时换。

首先还是Date的from(Instant instant)方法:

其次是将Instant对象创建出来传递给Date.from()方法:

Instant.now()是获取当前时间。

接着,调用Instant的plus(long amountToAdd, TemporalUnit unit)方法来延长时间。

第一个参数是时间数值,第二个参数时间单位。

例如这里的1秒钟:

TemporalUnit是一个接口,它有一个实现类,叫ChronoUnit。

ChronoUnit是一个枚举类,专门存放时间单位的:

它里面有16个时间单位:

NANOS(纳秒)MICROS(微秒)MILLIS(毫秒)SECONDS(秒)MINUTES(分钟)HOURS(小时)HALF_DAYS(半天,如AM / PM。)DAYS(整天)WEEKS(周)MONTHS(月)YEARS(年)DECADES(十年)CENTURIES(世纪)MILLENNIA(千年)ERAS(时代)FOREVER(永远)

但是,我们日常开发中不需要那么多。

常用的有以下6个:

SECONDS(秒)MINUTES(分钟)HOURS(小时)DAYS(整天)WEEKS(周)MONTHS(月)

所以,你需要什么时间单位就用什么时间单位。

例如,我想要1小时:

以上只是作为一个扩展知识介绍给大家,希望对大家有用。

5.中断线程

回到本章内容中来,awaitUntil​(Date deadline)方法的用法我们已掌握。

awaitUntil​(Date deadline)方法会使当前线程进行等待,被等待的线程可以被中断,那么我们来看看中断被等待的线程会怎样。

还是第3小节的例子,我们让主线程去执行中断线程的任务。

中断线程需要在持有锁的情况下才能进行,所以得让主线程获取锁:

在获取锁之前让主线程睡1秒钟,目的是让其他线程抢到锁然后进行等待:

主线程获取到锁之后,就可以中断其他线程了:

例子改写完毕。

运行程序,执行结果:

从运行结果来看,符合预期。中断被等待的线程只会执行catch或throws。

6.主动唤醒被等待的线程signal()/signalAll()方法

在前面演示了因超出线程等待的截止时间而唤醒的例子,我们发现这种情况下,awaitUntil​(Date deadline)方法会返回false。接下来,想知道主动唤醒被等待的线程awaitUntil​(Date deadline)方法返回什么。

还是上一小节的例子,只不过将中断线程的代码换成signal()/signalAll()方法。

以下是需要被替换的代码:

替换后的代码:

例子改写完毕。

运行程序,执行结果:

从运行结果来看,符合预期。线程在等待大约1秒钟之后被我们主动唤醒。而且awaitUntil​(Date deadline)方法返回true,说明是调用Condition对象的signal()/signalAll()方法主动唤醒的。

最后,希望大家可以把这个例子照着写一遍,然后再自己默写一遍,方便以后碰到类似的面试题可以轻松应对。

祝大家编码愉快!

GitHub

本章程序GitHub地址:

总结await()方法使当前线程在等待,直到它被唤醒,通常由被唤醒或中断。await​(long time, TimeUnit unit)方法造成当前线程在等待,直到它被唤醒,通常由被通知或中断或等待超时。当线程因超时自动唤醒时方法返回false,被通知唤醒返回true。awaitNanos​(long nanosTimeout)方法造成当前线程在等待,直到它被唤醒,通常由被通知或中断或等待超时。当返回值大于0时,说明是调用Condition的signal()/signalAll()方法主动唤醒被等待的线程,否则是等待超时。线程被等待的时间 = 线程最长等待时间 - awaitNanos​(long nanosTimeout)方法返回值当awaitNanos​(long nanosTimeout)返回值大于0时,就是我们主动调用Condition对象的signal()/signalAll()方法唤醒被等待的线程,即await​(long time, TimeUnit unit)方法返回true;否则就是超过被等待的线程最长等待时间,自动唤醒。awaitUntil​(Date deadline)方法造成当前线程在等待,直到它被唤醒,通常由被通知或中断或超过截止时间,自动唤醒。当被唤醒时,若已过截止时间返回false,否则返回true。signal()方法唤醒正在此对象监视器上等待的单个线程,选择是随机的。signalAll()方法作用是唤醒正在此对象监视器上等待的所有线程。

至此,Java中Condition对象的awaitUntil(Date deadline)方法相关内容讲解先告一段落,更多内容请持续关注。

答疑

如果大家有问题或想了解更多前沿技术,请在下方留言或评论,我会为大家解答。

上一章

“全栈2019”Java多线程第三十五章:如何获取线程被等待的时间?

下一章

“全栈2019”Java多线程第三十七章:如何让等待的线程无法被中断

学习小组

加入同步学习小组,共同交流与进步。

方式一:关注头条号Gorhaf,私信“Java学习小组”。方式二:关注公众号Gorhaf,回复“Java学习小组”。全栈工程师学习计划

关注我们,加入“全栈工程师学习计划”。

版权声明

原创不易,未经允许不得转载!

标签: #java 等待线程结束