shutdown()保留并执行队列中所有已提交任务,队列不修改;shutdownNow()立即清空队列、剥离未执行任务并返回List,触发队列物理移除操作。

核心区别在于:shutdown() 会**保留并执行完队列中所有已提交任务**;shutdownNow() 则**立即清空队列,把未执行的任务全部剥离出来返回**——这是两者在等待队列处理上的物理分水岭。
shutdown():队列任务照常流转,不删不弃
调用后,线程池状态变为 SHUTDOWN,但工作队列(如 LinkedBlockingQueue、ArrayBlockingQueue)保持原状。所有已入队但尚未开始执行的任务,仍会被后续空闲线程按顺序取出、执行。队列本身不被修改,也不返回任何任务引用。
- 队列中任务继续参与调度,直到全部完成
- 不会调用
workQueue.drainTo()或类似清空操作 - 若任务执行耗时长或线程数少,队列可能长时间非空
shutdownNow():队列被强制“抽干”,任务物理移出
该方法内部明确执行 drainQueue(),即遍历并批量移除队列中所有待执行的 Runnable 任务,将其封装为 List
- 清空动作是原子性、不可逆的物理移除
- 返回的 List 中任务未被运行,也未被取消(只是未入队执行)
- 即使队列实现不支持 drainTo(如 SynchronousQueue),也会尝试逐个 remove
为什么说这是“物理”分水岭?
不是语义差异,而是内存层面的操作实质不同:
- shutdown() 对队列对象不做任何写操作,仅改变线程池状态和线程行为
- shutdownNow() 必然触发队列结构变更:节点摘除、数组清空、引用断开——任务对象从队列容器中被真实剥离
- 这一动作可被监控工具直接观测到(如 queue.size() 从 N 突变为 0)
实际影响示例
假设队列中有 5 个待执行任务:
- 用 shutdown() → 这 5 个任务仍在线程池掌控下,最终都会被执行(除非 JVM 退出)
- 用 shutdownNow() → 队列瞬间变空,5 个任务作为 List 返回,线程池不再持有它们的任何引用

















