ThreadPoolExecutor 的线程回收由线程池自主控制而非 GC 触发:空闲超时、shutdown 渐进退出、shutdownNow 强制中断,且仅当 poolSize > corePoolSize、空闲≥keepAliveTime、队列为空时才收缩线程数。

ThreadPoolExecutor 的线程回收不是由 GC 主动触发的,而是由线程池自身根据空闲状态、存活时间、任务队列和运行状态等条件主动控制的。核心在于 工作线程(Worker)如何自我终止,以及线程池何时允许其退出。
线程空闲超时后自动退出
当线程池启用 allowCoreThreadTimeOut(false)(默认),核心线程即使空闲也不会被回收;若设为 true,则所有线程(包括核心线程)都受 keepAliveTime 约束。
Worker 线程在执行完一个任务后,会调用 getTask() 尝试从阻塞队列中获取下一个任务:
- 若队列非空,立即返回任务,继续执行
- 若队列为空,进入阻塞等待:对
LinkedBlockingQueue调用poll(keepAliveTime, unit) - 若等待超时仍未取到任务,
getTask()返回null,Worker 线程随即退出循环并结束生命周期
线程池 shutdown 后的渐进式回收
调用 shutdown() 后,线程池不再接受新任务,但会继续处理已提交的任务和队列中剩余任务:
立即学习“Java免费学习笔记(深入)”;
- 正在运行的 Worker 不会立即中断,而是完成当前任务后再次调用
getTask() - 此时
getTask()检测到isShutdown() && workQueue.isEmpty(),会返回null - Worker 退出循环,线程自然终止
- 未启动的 Worker(如因队列满而被拒绝的任务)不会被创建
线程池 stop(shutdownNow)的强制回收
调用 shutdownNow() 会:
- 尝试中断所有正在运行的 Worker 线程(通过
thread.interrupt()) - 清空任务队列,并返回其中未执行的任务列表
- Worker 若在阻塞中(如
take()或poll()),会抛出InterruptedException,捕获后通常直接返回null,从而退出 - 注意:是否真正停止取决于任务本身是否响应中断(例如是否检查
Thread.interrupted()或是否使用可中断的阻塞操作)
线程数收缩的关键前提
线程池不会“主动降低”线程数,只有满足以下全部条件时,空闲线程才可能退出:
- 线程池处于运行或关闭状态(非
STOP或TERMINATED) -
poolSize > corePoolSize(即存在非核心线程) - 当前线程空闲时间 ≥
keepAliveTime - 任务队列为空(或无法再获取新任务)
一旦线程退出,poolSize 减少,后续若有新任务且 poolSize ≤ corePoolSize,仍会优先复用现有线程或新建核心线程,而非恢复已退出的线程。


















