您的位置 首页 java

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

难度

初级

学习时间

30分钟

适合人群

零基础

开发语言

Java

开发环境

  • JDK v11
  • IntelliJIDEA v2018.3

友情提示

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

1.温故知新

前面在 一章中介绍了 Condition对象的await()方法与signal()/signalAll()方法

在 一章中介绍了 Condition对象的await​(long time, TimeUnit unit)方法

在 一章中介绍了 Condition对象的awaitNanos​(long nanosTimeout)方法

在 一章中介绍了 Condition对象的awaitUntil​(Date deadline)方法。

现在我们来讲解 Condition对象的awaitUninterruptibly()方法。

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. 让等待的线程无法被中断 awaitUninterruptibly()方法

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

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

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

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

以上四个方法均可以使线程等待,但是 被等待的线程都可以被中断

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

awaitUninterruptibly()方法可以让被等待的线程无法被中断:

awaitUninterruptibly()方法在Condition接口中的源码:

将注释翻译成中文:

中文注释全文:

造成当前线程等待,直到它被唤醒。
 

去掉注释版:

awaitUninterruptibly()方法造成当前线程等待,直到它被唤醒。

访问权限

void :awaitUninterruptibly()方法无返回值。

awaitUninterruptibly()方法只能被对象调用。

参数

无。

抛出的异常

无。

应用

方法名awaitUninterruptibly是await和Uninterruptibly单词的组合。单词Uninterruptibly翻译过来就是不可中断的意思。

下面,我们就来试试awaitUninterruptibly()方法。

在演示awaitUninterruptibly()方法之前,我们先看看之前四个可以被中断的等待方法其中之一的await()方法效果,然后将await()方法改为awaitUninterruptibly()方法再看看效果。

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

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

然后,创建出3个线程:

接着,启动线程:

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

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

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

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

因为await​()方法会抛出异常,所以我们需要使用catch或throws处理一下:

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

例子书写完毕。

运行程序,执行结果:

从运行结果来看,符合预期。线程被等待之后没有主动唤醒和中断的情况下醒不来。

因调用Condition对象的await()方法等待的线程是可以被中断的,下面我们来让主线程去中断这些被等待的线程。

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

在获取锁之前让主线程睡1秒钟:

在获取锁之后中断其他线程:

例子改写完毕。

运行程序,执行结果:

从运行结果来看,符合预期。因调用Condition对象的await()方法等待的线程是可以被中断的。

接下来,我们将await()方法换成awaitUninterruptibly()方法:

awaitUninterruptibly()方法没有抛出异常,所以需要将catch代码块移除:

移除后的代码:

例子改写完毕。

运行程序,执行结果:

从运行结果来看,符合预期。 因调用Condition对象的awaitUninterruptibly()方法等待的线程是无法被中断的。

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

因调用Condition对象的awaitUninterruptibly()方法等待的线程是无法被中断的,只能被主动唤醒。

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

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

替换后的代码:

例子改写完毕。

运行程序,执行结果:

从运行结果来看,符合预期。线程在等待大约1秒钟之后被我们主动唤醒。

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

祝大家编码愉快!

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。
  • awaitUninterruptibly()方法造成当前线程等待,直到它被唤醒。
  • signal()方法唤醒正在此对象监视器上等待的单个线程,选择是随机的。
  • signalAll()方法作用是唤醒正在此对象监视器上等待的所有线程。

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

答疑

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

上一章

下一章

“全栈2019”Java多线程第三十八章:从零手写一个线程安全缓冲区

学习小组

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

  • 方式一:关注头条号Gorhaf,私信“Java学习小组”。
  • 方式二:关注公众号Gorhaf,回复“Java学习小组”。

全栈工程师学习计划

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

版权声明

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

文章来源:智云一二三科技

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

文章地址:https://www.zhihuclub.com/176012.shtml

关于作者: 智云科技

热门文章

网站地图