线程池子线程的终止Shutdown()、ShutdownNow()
背景
之前某需求在触发流控时需要中断ExcutorService中的子线程,发现无论Shutdown、ShutdownNow方法都无法直接停止子线程,今天看到线程的interrupt()方法才了解如何停止。
stop() 和 interrupt()
stop方法
stop() 方法会真的杀死线程,不给线程喘息的机会,如果线程持有 ReentrantLock 锁,被 stop() 的线程并不会自动调用 ReentrantLock 的 unlock() 去释放锁,那其他线程就再也没机会获得 ReentrantLock 锁,类似的方法还有 suspend() 和 resume() 方法。故已不建议使用。
interrupt方法
interrupt() 方法仅仅是通知线程,线程有机会执行一些后续操作,同时也可以无视这个通知。
被 interrupt 的线程,是怎么收到通知的呢?一种是异常,另一种是主动检测。
异常
-
当线程 A 处于 WAITING、TIMED_WAITING 状态时,如果其他线程调用线程 A 的 interrupt() 方法,会使线程 A 返回到 RUNNABLE 状态,同时线程 A 的代码会触发 InterruptedException 异常
-
当线程 A 处于 RUNNABLE 状态时,并且阻塞在IO上时。如阻塞在java.nio.channels.InterruptibleChannel 上时,如果其他线程调用线程 A 的 interrupt() 方法,线程 A 会触发 java.nio.channels.ClosedByInterruptException 这个异常;而阻塞在 java.nio.channels.Selector 上时,如果其他线程调用线程 A 的 interrupt() 方法,线程 A 的 java.nio.channels.Selector 会立即返回。
tips: 这里的状态为Java线程状态:NEW(初始化状态)RUNNABLE(可运行 / 运行状态)BLOCKED(阻塞状态)WAITING(无时限等待)TIMED_WAITING(有时限等待)TERMINATED(终止状态)
主动检查
线程处于 RUNNABLE 状态,并且没有阻塞在某个 I/O 操作上,得依赖线程 A 主动检测中断状态。
如果其他线程调用线程 A 的 interrupt() 方法,那么线程 A 可以通过 isInterrupted() 方法,检测是不是自己被中断。
public class Main { public static void main(String[] args) throws InterruptedException { Thread t = new Thread(() -> { for (int i = 0; i < 10000000; i++) { System.out.println(i); if (Thread.currentThread().isInterrupted()) { System.out.println("find Interrupted"); break; } } }); ExecutorService executors = Executors.newFixedThreadPool(1); // 线程池执行 System.out.println("excute"); executors.execute(t); // 等待0.5秒 Thread.sleep(500); // 线程池中断 executors.shutdownNow(); t.join(); } }
如果子线程不检测isInterrupted()并主动停止,那么会继续运行下次。
中断标记与清楚
interrupt()会给对象线程打上中断标记,而捕获InterruptedException异常会清除标记。
Thread.currentThread().isInterrupted()不会清除标记。
shutdown()和shutdownNow()
shutdown方法只会取消等待中的任务,而shutdownNow方法还会给执行中的任务打上中断标记。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?