在开始本文之前,需要了解线程的状态,分别是:
//更详细的解释可以见源码 Thread.class 中的 State
public enum State{
NEW,//新建状态
RUNNABLE,//运行状态
BLOCKED,//阻塞状态
WAITING,//等待状态
TIMED_WAITING,//有时间限制的等待状态
TERMINATED;//终止状态
}
线程暂停、中断
1.线程如何中断?
- 使用
interrupt()
中断,给线程设置一个中断标志,本地方法
interrupt0();// Just to set the interrupt flag
然后可以通过方法isInterrupted()
或interrupted()
查询线程的是否被中断而进行其他的操作。 - 如果线程处于
BLOCKED
WAITING
TIMED_WAITING
状态时,则会触发中断异常InterruptedException
,并且中断标志位会被清除,如果是锁状态BLOCKED
并且在做 IO 操作,则触发ClosedByInterruptException
异常,同样我们可以在捕获异常中做所谓的暂停操作或其他。 - 在其他状态中,仅仅是设置中断标志位,不抛异常。
需注意的是,查询中断状态的方法中 isInterrupted()
不会重置中断标志位,而 interrupted()
会重置中断标志位。如果想保持线程的中断标志不改变,调用 isInterrupted()
即可,或者调用 interrupted()
后再次调用中断 interrupt()
,但线程运行中不能保证时间上的连续性,有可能导致其他地方查询线程中断情况时,线程中断标志已被重置而出现其他的问题。
2.当线程启动后,只有运行态,即 RUNNABLE
,如果不做中断标志判断,能否暂停或停止?
答案可以是能,也可以是不能。如果不介意 stop()
所带来的不安全问题,那么是可以停止(非暂停),调用后立刻抛出 ThreadDeath error
终止线程,但该方法存在风险,自行判断能否接受,关于 stop()
的风险,可以参考下面这篇文章 Java中的线程Thread方法之—stop() ,或查阅其他资料。除了这个方法,又不做中断判断,除了自行设置 中断/暂停标志 外,你的线程,嗯,对不起,当你 start()
后,它就不归你控制了。
3.线程的暂停操作
通过中断标志位判断,或者在中断异常中暂停线程,然后可以使用 Object.wait()
等操作暂停,等待被唤起,或者保存此时线程内部对象状态,待需恢复时重新启动该线程。
线程终止、取消
1.怎么停止处于工作状态的线程,怎么取消一个未进入运行状态的线程?
- 使用中断方法
interrupt()
通过标志位或捕获异常块return
出去。 - 取消一个未进入运行状态的线程,那么此时该线程处于
NEW
状态,或者start()
后的可运行状态,使用中断后,在run()
第一句判断是否处于中断中,若是,直接return
出线程。 - 线程启动后,它处于可运行状态,不能保证当前线程一定是处于非运行状态,所以可以使用
Future
或FutureTask
的cancel(boolean mayInterruptIfRunning)
来取消线程,通过传入参数控制是否中断线程(如果线程已经启动的话),如果线程未运行,则直接取消;如果已运行,则启动中断线程流程。
总结:
- 当线程被启动,只有通过一些标志位的判断来中断运行过程,如果工作线程内部执行是一个顺序过程(A>B>C>D>E…)大量操作,且优先级一致,则会嵌套一堆判断,所以对于有些可能被取消,但线性执行的线程,我现在没有一个比较好的解决方案,如果有,以后再填坑。
- 如果是线性执行,大量操作,但存在操作优先级的话,可以只判断优先级高的操作,能减轻代码量,但还是没什么用。
- 如果可用循环执行,嵌套
for
的话,加个中断位判断;如果是有sleep
wait
等操作,加个异常捕获操作。对于这种理想型线程,自定义一个标志位,或者利用Future
的cancel(bool)
,轻松达到取消暂停线程的目的。