Fork me on GitHub

Java 线程总结(四)

Java 线程总结(四) —— 线程的中断

1、在 Java 中,停止一个线程的主要机制是中断,中断并不是强迫终止一个线程,它是一种协作机制,是给线程传递一个取消信号,但是由线程来决定如何以及何时退出。

2、每个线程都有一个标志位,表示该线程是否被中断了。被中断了为 true,没有被中断或默认值为 false。

3、Thread 类定义了以下关于中断的方法:

public boolean isInterrupted():就是返回对应线程的中断标志位是否为 true。

public void interrupt()。

public static boolean interrupted() interrupted() 是静态方法,实际会调用 Thread.currentThread() 操作当前线程。返回当前线程的中断标志位是否为 true,但它还有一个重要的副作用,就是清空中断标志位,也就是说,连续两次调用 interrupted(),第一次返回的结果为 true,第二次一般就是 false「除非同时又发生了一次中断」。

4、线程对中断的反应
interrupt() 对线程的影响与线程的状态和正在进行的 IO 操作有关,我们先主要考虑线程的状态:

RUNNABLE:线程在运行或具备运行条件只是在等待操作系统调度。如果线程在运行中,且没有执行 IO 操作,interrupt() 只是会设置线程的中断标志位,没有任何其它作用。线程应该在运行过程中合适的位置检查中断标志位

WAITING/TIMED_WAITING:线程在等待某个条件或超时。在这些状态时,对线程对象调用 interrupt() 会使得该线程抛出 InterruptedException,需要注意的是,抛出异常后,中断标志位会被清空,而不是被设置。

BLOCKED:线程在等待锁,试图进入同步块。如果线程在等待锁,对线程对象调用 interrupt() 只是会设置线程的中断标志位,线程依然会处于 BLOCKED 状态,也就是说,interrupt() 并不能使一个在等待锁的线程真正”中断”。在使用 synchronized 关键字获取锁的过程中不响应中断请求,这是 synchronized 的局限性。 如果这对程序是一个问题,应该使用显式锁,它支持以响应中断的方式获取锁。

NEW/TERMINATED:线程还未启动或已结束。如果线程尚未启动 (NEW),或者已经结束 (TERMINATED),则调用 interrupt() 对它没有任何效果,中断标志位也不会被设置。

5、捕获到 InterruptedException,通常表示希望结束该线程,线程大概有两种处理方式:

1.向上传递该异常,这使得该方法也变成了一个可中断的方法,需要调用者进行处理。

2.有些情况,不能向上传递异常,比如 Thread 的 run 方法,它的声明是固定的,不能抛出任何受检异常,这时,应该捕获异常,进行合适的清理操作,清理后,一般应该调用 Thread的 interrupt 方法设置中断标志位,使得其他代码有办法知道它发生了中断。

6、IO 操作
如果线程在等待 IO 操作,尤其是网络 IO,则会有一些特殊的处理:

如果 IO 通道是可中断的,即实现了 InterruptibleChannel 接口,则线程的中断标志位会被设置,同时,线程会收到异常 ClosedByInterruptException。

如果线程阻塞于 Selector 调用,则线程的中断标志位会被设置,同时,阻塞的调用会立即返回。

7、InputStream 的 read 调用,该操作是不可中断的,如果流中没有数据,read 会阻塞 (但线程状态依然是 RUNNABLE),且不响应 interrupt(),与 synchronized 类似,调用 interrupt() 只会设置线程的中断标志,而不会真正”中断”它。

8、如何正确地取消/关闭线程?
interrupt 方法不一定会真正”中断”线程,它只是一种协作机制,如果不明白线程在做什么,不应该贸然的调用线程的 interrupt 方法,以为这样就能取消线程。

对于以线程提供服务的程序模块而言,它应该封装取消/关闭操作,提供单独的取消/关闭方法给调用者,外部调用者应该调用这些方法而不是直接调用 interrupt。

在 Java 中如何取消/关闭线程,主要依赖的技术是中断,但它是一种协作机制,不会强迫终止线程。作为线程的实现者,应该提供明确的取消/关闭方法,并用文档描述清楚其行为,作为线程的调用者,应该使用其取消/关闭方法,而不是贸然调用 interrupt。

参考博客

Java 编程的逻辑 - 线程的中断

-------------本文结束感谢您的阅读-------------

本文标题:Java 线程总结(四)

文章作者:Yan ChongSheng

发布时间:2018年08月17日

最后更新:2018年08月24日

原始链接:yanchongsheng.github.io/2018/08/17/Java-Java-Thread-2018-08-17-Java线程总结-四/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

开启打赏模式
Powered By Valine
v1.5.2