直接监控拒绝策略触发次数是最敏感可靠的过载判断信号,通过getrejectedexecutioncount()实时采样、滑动窗口统计、micrometer上报、prometheus告警、上下文日志记录及自动降级备份实现闭环治理。

直接监控拒绝策略触发次数,是判断线程池是否持续过载最敏感、最可靠的信号之一。它不像活跃线程数或队列大小那样存在滞后或误判,而是明确告诉你:系统已开始丢任务。
用 getRejectedExecutionCount() 做实时采样
ThreadPoolExecutor 提供了线程安全的 getRejectedExecutionCount() 方法,每次拒绝都会原子递增,无需额外同步,是监控的黄金入口。
- 每秒调用 1–2 次即可,频率太高无意义,还可能影响 /actuator/prometheus 接口性能
- 建议用滑动窗口(如最近 10 秒)累计变化量,而非只看绝对值——避免初始化为 0 的干扰
- 连续 3 次采样中,每秒增量 ≥ 3 次,可判定为持续过载,不是毛刺
结合 Micrometer 上报并配置 Prometheus 告警
单纯记录数字没用,得让指标可查、可告、可下钻。
- 在自定义 RejectedExecutionHandler 的 rejectedExecution 方法里,调用 Counter.increment(),打上 pool 名称标签,例如:.tag("pool", "payment-processor")
- Prometheus 查询示例:rate(threadpool_rejection_count_total{job="myapp"}[1m]) > 0.2,表示每秒平均拒绝超 0.2 次(即 1 分钟内超 12 次)
- Grafana 中按 pool 标签拆图,点击下钻能快速定位是哪个业务线程池出问题
拒绝时同步记录上下文,辅助根因分析
告警不能只说“被拒了”,得告诉运维“为什么拒、拒的是谁、当时多忙”。
- 在拒绝逻辑中打印轻量日志:log.warn("REJECT [{}]: queue={}, active={}, taskType={}", poolName, q.size(), executor.getActiveCount(), task.getClass().getSimpleName())
- 避免打印完整参数或堆栈,防止日志刷屏;但关键字段(如订单 ID、用户 ID)若能从 Runnable 中提取,应保留
- 配合采集 executor.getQueue().size() 和 getActiveCount(),可区分是“队列塞满”还是“线程全忙+队列也满”
联动执行降级与自动备份,不止于告警
告警是起点,不是终点。真正高可用的系统会在拒绝发生时自动响应。
- 拒绝策略中不直接发 MQ 或写 DB,而是将任务 offer 到一个内存缓冲队列(如 ConcurrentLinkedQueue),由后台线程异步刷出
- 备份目标优先走 RocketMQ/Kafka,序列化时带上时间戳和原始线程池名,便于后续重放或归因
- 同步触发限流开关(如 Sentinel 的流控规则),降低上游流入速率,形成“监控→告警→降级→恢复”闭环
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











