跳到主要内容
📖 本章预览

本章为预览版本,展示部分核心内容。完整内容包含详细源码解析、实战代码和面试要点,加入知识星球即可解锁全部章节。

第十一章:发版重启时线程池里的任务去哪了 — 优雅关闭

本章目标:理解 DtpLifecycleSupport 的两种关闭策略,掌握 Future.cancel(true) 的含义、awaitTermination 超时处理、InterruptedException 中断协议三个 Java 并发细节。


11.1 两难选择

应用关闭时,线程池中可能还有未完成的任务。你面临两难:

  • shutdownNow():立即中断所有线程,队列中的任务直接丢失
  • shutdown():不接受新任务,但等待已提交任务完成 — 如果有任务卡住,可能无限等待

DynamicTP 通过 DtpLifecycleSupport 提供了可配置的优雅关闭策略:选择等待还是立即中断 + 限时等待兜底 + Future 取消 + 异步关闭


11.2 internalShutdown — 核心关闭方法

@Slf4j
public class DtpLifecycleSupport {

/**
* @param waitForTasksToCompleteOnShutdown true=等待任务完成, false=立即中断
* @param awaitTerminationSeconds 最大等待秒数
*/
public static void internalShutdown(
ExecutorService executor,
String threadPoolName,
boolean waitForTasksToCompleteOnShutdown,
int awaitTerminationSeconds) {
if (Objects.isNull(executor)) {
return;
}
log.info("Shutting down ExecutorService, threadPoolName: {}",
threadPoolName);

if (waitForTasksToCompleteOnShutdown) {
// 等待模式:不接受新任务,但让队列中的任务跑完
executor.shutdown();
} else {
// 立即模式:尝试中断正在执行的任务,返回未执行的任务列表
for (Runnable remainingTask : executor.shutdownNow()) {
cancelRemainingTask(remainingTask);
}
}
// 无论哪种模式,都限时等待终止
awaitTerminationIfNecessary(executor, threadPoolName,
awaitTerminationSeconds);
}
}

11.3 cancelRemainingTask — Future 取消

protected static void cancelRemainingTask(Runnable task) {
if (task instanceof Future) {
((Future<?>) task).cancel(true);
}
}

为什么需要这一步?

shutdownNow() 返回的是未执行的 Runnable 列表。如果任务是通过 submit() 提交的,实际类型是 FutureTask。如果不调用 cancel(true)

  • 调用 future.get() 的线程会永久阻塞(因为任务永远不会执行了)
  • cancel(true) 会设置 Future 的取消状态,让 get() 抛出 CancellationException
  • 参数 true 表示允许中断正在执行的任务

11.4 awaitTerminationIfNecessary — 限时等待

private static void awaitTerminationIfNecessary(
ExecutorService executor,
String threadPoolName,
int awaitTerminationSeconds) {
if (awaitTerminationSeconds <= 0) {
return; // 不等待,直接返回
}
try {
if (!executor.awaitTermination(
awaitTerminationSeconds, TimeUnit.SECONDS)) {
// 超时了,任务还没全部完成
log.warn("Timed out while waiting for executor {} to terminate",
threadPoolName);
}
} catch (InterruptedException ex) {
// 等待过程中被中断
log.warn("Interrupted while waiting for executor {} to terminate",
threadPoolName);
Thread.currentThread().interrupt(); // 恢复中断标志
}
}

三个关键细节:

  1. awaitTerminationSeconds <= 0 时不等待,直接返回 — 适用于"fire and forget"场景

🔒 解锁完整内容

本章剩余内容需要解锁后查看

以上仅为本章部分预览内容,完整内容包含更多深度源码解析、实战代码和面试要点。

加入知识星球你将获得:

  • ✅ 全部 12 章完整内容 + 持续更新
  • ✅ 配套源码 + 实战项目
  • ✅ 一对一答疑 + 面试辅导
  • ✅ 简历优化 + 内推机会

📚 本章完整目录

以下为本章完整目录结构,加入知识星球即可解锁全部内容。

11.5 shutdownGracefulAsync — 异步优雅关闭

11.6 生命周期入口

11.7 完整关闭流程

11.8 本章涉及的设计模式与并发细节