大量出现 WAITING (parking) + LinkedBlockingQueue.take() 线程栈 = 线程池耗尽 / 阻塞死锁

现在的场景完全符合 :同一个线程池嵌套提交任务 → 线程池所有线程都被占满 → 新任务进队列排队 → 所有线程都在等子任务执行 → 最终全部卡死等待
这就是线程池死锁,不是正常空闲!
1. 为什么你这个写法一定会出大量 WAITING?
你的代码逻辑:
java
运行
// 方法A 使用 线程池1 执行
public void methodA() {
executor1.submit(() -> {
// 内部 方法B 也用 同一个线程池1 提交
methodB(); // 内部又 executor1.submit(...)
});
}
致命问题:线程池线程数量有限
假设线程池配置:
- 核心线程 = 5
- 最大线程 = 5
- 队列 = 无界队列
执行流程:
- 5 个任务进来 → 占满全部 5 个线程
- 每个任务内部又提交新任务到同一个线程池
- 新任务只能进队列等待
- 但所有线程都在运行中,且在等待自己提交的子任务完成
- 线程池没有空闲线程去处理队列里的任务
- 最终:所有线程都卡死在 WAITING 状态
这就是线程池死锁 ,日志里就会大批量出现你截图里的栈:
plaintext
WAITING (parking)
at java.util.concurrent.LinkedBlockingQueue.take()
2. 一眼判断:这不是空闲,是死锁!
正常空闲(少量)
- 只有闲置线程会出现这个栈
- 线程数 << 最大线程数
- 任务执行正常
你的情况(大量)
- 所有工作线程全部是这个状态
- 任务不执行、不结束、不报错
- CPU 很低、队列堆积
- 典型:线程池满了 + 嵌套提交同一线程池 + 阻塞等待
3. 最快修复方案(立刻解决)
方案 1:最推荐 → 父子任务用不同线程池隔离
java
运行
// 父任务线程池
ExecutorService parentExecutor = Executors.newFixedThreadPool(5);
// 子任务线程池(独立池,互不影响)
ExecutorService childExecutor = Executors.newFixedThreadPool(5);
方法 A 用 parent 方法 B 用 child绝对不会死锁。
方案 2:临时急救 → 线程池用非无界队列 + 拒绝策略
不推荐,但能快速避免卡死:
java
运行
new ThreadPoolExecutor(
5, 5,
0L, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(10), // 有界队列
new ThreadPoolExecutor.CallerRunsPolicy() // 满了让调用线程执行
);
方案 3:代码层面 → 不要嵌套提交同一线程池
如果必须用同一个池:
- 不要在任务内部同步等待 子任务(
future.get()) - 改成纯异步,不等待
4. 现在的问题 100% 确诊
** 大量 WAITING (parking) + LinkedBlockingQueue.take ()
- 同一个线程池嵌套提交= 线程池死锁 **
总结
- 不是正常空闲 ,是线程池死锁
- 根因:同一线程池嵌套提交任务,线程耗尽,队列任务无法执行
- 最优解:父子任务用两个独立线程池