JDK 19 起 ExecutorService 实现了 AutoCloseable,try-with-resources 看上去让线程池关闭变得简单。这篇逐一量出 close() 到底做了什么:什么时候阻塞、被中断时怎么办、对 commonPool 和定时线程池有什么特殊行为,以及 shutdownNow() 的边界。
shutdown() 调用返回用时 0 ms;1.2 s 后:完成 4 个、被中断 0 个,isTerminated() = true shutdown() + awaitTermination 调用返回用时 900 ms;1.2 s 后:完成 4 个、被中断 0 个,isTerminated() = true shutdownNow() 调用返回用时 6 ms;1.2 s 后:完成 0 个、被中断 2 个,返回的未开始任务 2 个,isTerminated() = true close() 调用返回用时 909 ms;1.2 s 后:完成 4 个、被中断 0 个,isTerminated() = true
150 ms 时中断了正在 close() 的线程:close() 在 159 ms 后返回,调用线程中断标志 = true;随后完成 0 个、被中断 2 个、未开始(被丢弃)2 个
commonPool().close() 用时 0 ms,返回时任务已完成 = false,isShutdown() = false;再提交一个任务仍然能执行 自建 ForkJoinPool.close() 用时 441 ms,返回时任务已完成 = true,isTerminated() = true CompletableFuture.runAsync(默认用 commonPool)之后 commonPool().close() 用时 0 ms,返回时任务已完成 = false(close 没有等它)
默认策略:getExecuteExistingDelayedTasksAfterShutdownPolicy() = true,getContinueExistingPeriodicTasksAfterShutdownPolicy() = false 350 ms 时 close():用时 1147 ms(延迟 1500 ms 的一次性任务被等到);周期任务在 close 前执行了 4 次、close 后共 4 次;延迟任务已执行 = true setContinueExistingPeriodicTasksAfterShutdownPolicy(true) + shutdown() 后 600 ms:周期任务共执行 8 次,isTerminated() = false(周期任务不停,池永远不会终止)
shutdownNow() 立即返回(0 ms),未开始任务 0 个;此时任务已结束 = false,isTerminated() = false awaitTermination(300 ms) = false(距 shutdownNow 约 302 ms);任务已结束 = false 继续 awaitTermination(5 s) = true,距 shutdownNow 共约 1399 ms(任务忙等 1500 ms,从提交后 100 ms 才调用 shutdownNow);任务已结束 = true 对照:JDK 17 与 JDK 21 上同样的 try-with-resources JDK 17 javac 退出码 1 | <jtmp>/j249b/Main.java:1: error: incompatible types: try-with-resources not applicable to variable type JDK 21 javac 退出码 0 运行: ok