并发编程 终止线程
本文将介绍如何终止线程以及如何终止线程池。
一、如何终止线程?
不建议使用 stop()
方法,它会直接杀死线程,可能会因启占有的锁未释放而影响后续其它线程操作。
建议使用 interrupt()
,它所作的事情是通知线程终止。线程可以在收到终止信号后进行一些后续操作并自行结束。
二、interrupt()
interrupt()
的作用是:通知线程应该结束。
需要注意的是,具体要结束还是要继续运行,可以由被通知的线程自行决定。
具体而言,对一个线程调用 interrupt()
时,
如果线程处于阻塞状态(调用了
wait()
、join()
、sleep()
方法),则线程的中断标志将被设为 true,并且退出阻塞状态并抛出一个 InterruptedException,JVM 会将触发异常时线程的中断标志重置,将中断标志重新设为 false如果线程处于正常活动状态,则线程的中断标志将被设为 true
如果线程正在获取锁,且该锁无法被
interrupt()
(synchronized、JUC 包下无法被中断的锁),则线程不会被interrupt()
影响
三、两阶段终止模式
1. 什么是两阶段终止模式?
所谓两阶段终止模式,就是将终止过程分为两个两个阶段:
- 阶段一:线程 A 向线程 B 发送终止指令
- 阶段二:线程 B 响应终止指令
2. 简单示例
1 |
|
2. 简单示例 - 考虑阻塞
如果线程处于阻塞状态(调用了
wait()
、join()
、sleep()
方法),则线程的中断标志将被设为 true,并且退出阻塞状态并抛出一个 InterruptedException,JVM 会将触发异常时线程的中断标志重置,将中断标志重新设为 false
因此,应该捕捉 InterruptedException,并重新设置线程的中断状态,如下:
1 |
|
3. 简单示例 - 自定义的线程终止标志位
此版代码主要解决这样一个问题:我们常常需要调用第三方方法,无法保证第三方方法中是否会对 InterruptedException 做正确处理,因此可以增加自定义的线程终止标志位。
1 |
|
四、终止线程池
线程池提供了两个方法:
shutdown()
:拒绝接收新任务;待正在执行的任务和等待队列的任务执行完成后,关闭线程池shutdownNow()
:拒绝接收新任务;中断正在执行的任务;将等待队列的任务作为方法返回值返回,丢弃等待队列中的任务;关闭线程池如果需要调用此方法,则在提交的任务中,需要应用两阶段终止模式处理线程的终止
参考
- Java 并发编程实战