You need to enable JavaScript to run this app. Spring Boot线程无法停止疑似内存泄漏 CompletableFuture多线程任务排查
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot线程无法停止疑似内存泄漏 CompletableFuture多线程任务排查

问题根因
  • 线程池未正确关闭:你在遍历departmentList的循环内部,每次循环都通过Executors.newFixedThreadPool(20)新建一个独立的线程池,且处理完当前部门的任务后从未主动关闭该线程池。newFixedThreadPool创建的线程池默认核心线程数为20,且核心线程不会超时回收,所有空闲核心线程会一直阻塞在任务队列的take()方法等待新任务,和你日志中栈追踪的逻辑完全对应。当应用停止时,这些没有被关闭的线程池的存活线程会被Tomcat检测到,抛出内存泄漏警告。
  • 线程池创建逻辑不合理:循环内反复创建线程池本身属于错误实践,反复创建销毁线程池会带来额外的性能开销,也提升了资源泄漏的概率。
修复建议
  • 全局复用线程池:不要在循环内创建线程池,建议直接使用SpringBoot提供的ThreadPoolTaskExecutor,在配置类中统一初始化线程池参数后全局注入使用,Spring会自动注册shutdown钩子,在应用停止时主动关闭线程池回收线程。
  • 手动创建线程池必须主动关闭:如果需要手动创建线程池,在单次任务处理完成后必须调用shutdown()方法主动触发线程池关闭,同时可以搭配awaitTermination()方法等待所有任务执行完成后再继续后续逻辑,参考代码:
executor.shutdown();
try {
  if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
    executor.shutdownNow();
  }
} catch (InterruptedException e) {
  executor.shutdownNow();
  Thread.currentThread().interrupt();
}
  • 优化线程池参数:可以给线程池设置allowCoreThreadTimeOut(true),允许核心线程在空闲一段时间后自动销毁,避免空闲线程长期驻留。
  • 调整futureList作用域:将futureList的定义移到部门循环内部,每次处理完一个部门的任务后,该列表可以被正常GC,避免额外内存占用。

内容的提问来源于stack exchange,提问作者linuxNoob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.22 01:54:03