callerrunspolicy 的核心逻辑是:当线程池无法接纳新任务时,由提交任务的线程(如主线程、tomcat worker 线程)同步执行 task.run(),实现反压控制;它不创建线程、不丢任务,但可能阻塞调用线程,需避免在关键路径滥用。

CallerRunsPolicy 的核心逻辑就是:当线程池无法接受新任务(队列已满、线程数已达上限)时,不丢弃任务,也不抛异常,而是**直接在提交任务的线程(即调用 execute() 方法的线程)中同步执行该任务**。
它怎么让“调用者”执行?
这里的“调用者”不是指任意用户代码,而是特指调用线程池 execute() 或 submit() 方法的那个线程。比如主线程、Web 容器线程(如 Tomcat 的 worker 线程)、定时任务线程等。
具体流程如下:
- 线程池判断当前无法接纳新任务(比如
workQueue.offer()失败且线程数已达maximumPoolSize); - 拒绝策略被触发,
CallerRunsPolicy.rejectedExecution()被调用; - 该方法内部直接调用
task.run()—— 注意是run(),不是start(); - 由于是同步调用,当前线程(即提交任务的线程)会阻塞,直到这个任务执行完成。
实际效果和典型场景
这种策略本质是一种反压(backpressure)机制,把压力反馈给上游:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 如果提交任务的是主线程,主线程就会卡住执行该任务,自然降低提交速度;
- 如果是在 Web 请求线程中提交(如 Spring 中异步调用),那么该 HTTP 请求的处理会被延迟,从而间接限制请求吞吐量;
- 它不会创建新线程,也不丢失任务,适合对任务可靠性要求高、但可接受响应变慢的场景。
使用时要注意什么?
虽然简单可靠,但容易引发意外阻塞:
- 避免在关键路径(如 UI 线程、Netty EventLoop、Servlet 线程)中无保护地使用,否则可能导致整个服务假死或超时;
- 任务本身不能耗时过长,否则调用线程长时间被占用,影响系统整体响应能力;
- 它只对
execute()生效;submit()返回Future,但拒绝时仍走同一策略,只是Future.get()会等到run()执行完才返回结果。
怎么设置?
创建线程池时显式传入即可:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4,
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue(10),
new ThreadPoolExecutor.CallerRunsPolicy()
);
也可以自定义策略继承 RejectedExecutionHandler,复用 task.run() 逻辑并增加日志或监控。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










