CallerRunsPolicy在拒绝任务时不丢弃也不抛异常,而是由提交任务的线程同步执行run();触发条件为线程池关闭或队列满且线程全忙;导致调用线程阻塞,形成反压限流。

当线程池拒绝任务时,CallerRunsPolicy 的核心逻辑是:**不丢弃任务,也不抛异常,而是让提交任务的线程(即调用 execute() 的线程)自己同步执行该任务**。这本质上是一种“降级”策略,把压力反向传递给调用方,避免系统崩溃,同时起到自然限流作用。
CallerRunsPolicy 的触发条件
它只在以下情况生效:
- 线程池已关闭(
isShutdown() == true); - 或线程池未关闭,但工作队列已满、核心线程和最大线程都在忙(即达到拒绝阈值)。
它是如何让“调用方执行”的
关键在于它的 rejectedExecution 方法实现非常简洁:
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run(); // ? 直接在当前线程(即调用 execute() 的线程)中运行任务
}
}
也就是说,原本由线程池异步执行的 Runnable,此时被同步调用 run() 方法——**没有新线程启动,没有入队,不返回,直接阻塞当前调用线程直到任务完成**。
实际效果与注意事项
这种策略会带来几个明显行为特征:
- 调用方线程(比如 Tomcat 的一个 worker 线程、或你主线程)会变慢,因为要亲自干活;
- 如果任务本身耗时长,会导致调用方吞吐骤降,甚至引发上游超时;
- 它不改变任务语义(不会丢失、不会重试),适合对一致性要求高、可接受延迟的场景;
- 它天然形成反压:上游提交越快,自己执行越多,速度越慢,从而倒逼上游减速。
怎么配置它
创建线程池时显式传入即可:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4,
60L, TimeUnit.SECONDS,
new ArrayBlockingQueue(10),
new ThreadPoolExecutor.CallerRunsPolicy() // ✅ 启用该策略
);
也可自定义子类扩展逻辑,比如记录日志、添加监控埋点后再调用 r.run()。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











