rejectedexecutionexception是线程池拒绝任务的明确信号,需结合堆栈判断策略类型,并关联qps、慢sql等指标分析资源水位与任务节奏错配。

直接看拒绝日志,能快速锁定线程池是否已满、任务是否在堆积、哪个环节卡住了。关键不是日志本身,而是日志背后反映的资源水位和任务节奏错配。
确认拒绝异常是否真实发生
先查日志中是否出现 RejectedExecutionException,这是最明确的信号。注意区分是业务代码主动抛出,还是线程池底层拒绝导致。常见堆栈开头为:
java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecutionjava.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy.rejectedExecutionjava.util.concurrent.ThreadPoolExecutor$DiscardPolicy.rejectedExecution
如果日志里只有“任务未执行”但没异常堆栈,可能是用了 DiscardPolicy 或自定义静默策略,需结合监控指标交叉验证。
关联时间点与业务流量特征
拒绝往往不是孤立事件,要拉通看:同一时间段内,是否对应着访问量突增、定时任务集中触发、或下游接口响应变慢?例如:
- 用
access.log统计每秒请求数(QPS),对比拒绝日志频次; - 检查数据库慢 SQL 日志、外部 HTTP 调用超时日志,确认是否因依赖变慢拉长了单任务耗时;
- 若拒绝集中在每天整点,大概率是定时批处理任务并发提交冲击线程池。
从拒绝日志反推线程池配置短板
拒绝发生时,线程池一定处于“队列满 + 线程数已达上限”状态。此时需立刻确认三个核心参数的实际值:
-
当前活跃线程数:是否长期等于
maximumPoolSize?说明线程全在跑,没空闲; -
任务队列长度:是否持续 > 80% 容量?比如
ArrayBlockingQueue(200)长期维持在 180+; - 拒绝率:单位时间内被拒任务数 ÷ 总提交数。超过 1% 就需干预,超过 5% 通常已影响业务可用性。
举例:某支付回调线程池配置为 core=20、max=50、queue=200,日志显示每分钟拒 300+ 任务——说明 queue 已撑满且 max 线程全忙,根本原因是单任务平均耗时从 200ms 升至 800ms,吞吐能力直接跌了 4 倍。
结合线程堆栈定位阻塞源头
光看拒绝日志不够,要抓取同一时刻的 jstack 输出,重点筛查:
- 状态为
BLOCKED的线程是否集中在某个锁(如synchronized方法、ReentrantLock.lock()); - 大量线程停在
SocketInputStream.read或JDBCConnection.await,说明卡在 I/O 或数据库连接获取; - 是否有线程长时间处于
WAITING (parking)且堆栈指向自定义 Future.get() 或 CountDownLatch.await(),提示任务内部存在串行等待逻辑。
这类阻塞不会让线程池报错,但会显著拖慢任务执行,间接导致后续任务排队甚至被拒。










