DiscardOldestPolicy 是线程池拒绝策略,当队列满时丢弃队首最老任务并尝试加入新任务;依赖 FIFO 队列如 ArrayBlockingQueue、LinkedBlockingQueue,不适用于 PriorityBlockingQueue 或 SynchronousQueue。

DiscardOldestPolicy 是 Java 线程池中一种拒绝策略,它的行为是:当线程池和任务队列都已满时,不直接丢弃新提交的任务,而是尝试丢弃**任务队列中最老的那个任务**(即队首、最早入队的任务),然后把当前新任务加入队列,争取让它后续被执行。
它怎么“丢弃最老任务”?
这个动作发生在 execute() 方法的拒绝流程中,核心逻辑在 ThreadPoolExecutor.DiscardOldestPolicy#rejectedExecution 方法里:
- 先检查线程池是否还在运行(
isShutdown() == false); - 如果队列非空(
!queue.isEmpty()),就调用queue.poll()—— 这会移除并返回队列头部元素(FIFO 队列下就是最先进入的任务); - 接着调用
queue.offer(command)尝试把新任务加进去; - 注意:这步
offer()可能失败(比如队列满了且是无界队列不会满,但如果是有界队列且刚腾出一个位置,通常成功;不过仍需注意并发下可能又被占满); - 如果
offer()成功,新任务进入队列等待执行;如果失败(极小概率),该任务仍被丢弃,但此时最老任务已被删,新任务也没塞进去——这种边界情况一般无需特别处理。
关键前提:队列必须支持 poll() 和 offer()
该策略依赖队列的 FIFO 行为,因此只适用于实现了 BlockingQueue 且按插入顺序排队的实现,例如:
-
ArrayBlockingQueue(有界、FIFO)✅ -
LinkedBlockingQueue(默认无界,FIFO)✅ -
PriorityBlockingQueue❌(按优先级排序,poll() 返回最小/最大优先级项,不是“最老”) -
SynchronousQueue❌(没有容量,不存储任务,“最老任务”概念不成立)
实际效果举例
假设线程池配置为:corePoolSize=1, maxPoolSize=1, queue = new ArrayBlockingQueue(2),当前状态:
- 1 个线程正在运行任务 A;
- 队列中有任务 B(先入)、任务 C(后入);
- 此时再 submit 任务 D → 触发拒绝策略;
-
DiscardOldestPolicy执行:queue.poll()移除 B,再queue.offer(D)把 D 加入队尾; - 最终队列内容变为:C、D;B 被丢弃,A 继续执行,C 和 D 按序等待。
要注意的细节
- 它丢弃的是“队列中最老任务”,不是“正在执行的最老线程”或“已提交但未入队的任务”;
- 如果队列为空(比如所有任务都在执行,没排队),
poll()返回 null,之后offer()仍会尝试添加新任务——此时相当于退化为“尽力添加”,不一定丢弃; - 该策略不保证新任务一定被执行(比如添加后线程池立即 shutdown);
- 它不抛异常、不记录日志,静默丢弃——如需可观测性,建议自定义策略包装日志。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











