线程池保护机制是防止系统雪崩的必要防线:必须使用有界队列(如ArrayBlockingQueue)、选用CallerRunsPolicy拒绝策略、按I/O密集型场景配置线程数与超时,并结合熔断监控实现主动防御。

处理耗时任务时,线程池容易因任务堆积、线程阻塞或资源耗尽而失稳。保护机制不是“可选配置”,而是防止系统雪崩的必要防线。
任务队列要设界,避免内存失控
无界队列(如 LinkedBlockingQueue 默认容量 Integer.MAX_VALUE)看似能扛住突发流量,但耗时任务会让队列持续积压,最终引发 OOM。必须用有界队列,比如 ArrayBlockingQueue(200),配合明确的容量预期。
- 队列大小建议按峰值 QPS × 平均耗时 × 安全系数(1.5~2)粗略估算
- 搭配监控:一旦队列长度长期 > 70% 容量,就该告警并排查任务是否异常变慢
- 切忌用 SynchronousQueue 处理耗时任务——它不缓存,会直接触发拒绝策略
拒绝策略选对类型,别让失败静默发生
耗时任务场景下,DiscardPolicy(静默丢弃)和 AbortPolicy(抛异常)都不够稳妥;CallerRunsPolicy 是更实用的选择:
- 它让提交线程自己执行任务,天然形成反压——调用方变慢,上游流量自然收敛
- 特别适合日志上报、异步通知等“重要但不紧急”的耗时操作
- 若业务要求零丢失,需自定义策略:把被拒任务序列化后写入 Redis 或 Kafka,再由后台消费者重试
线程数与超时要分场景配,不能拍脑袋
耗时任务本质是 I/O 密集型,线程数不能按 CPU 核心数硬套:
立即学习“Java免费学习笔记(深入)”;
- 核心线程数可设为 2 × CPU 核数 起步,最大线程数建议不超过 core × 3,防止上下文切换开销反噬性能
- keepAliveTime 设为 30~60 秒较合理——太短导致频繁创建销毁,太长又占着资源不放
- 务必设置 ThreadFactory 给线程命名(如 “io-pool-worker-%d”),方便排查哪个线程卡死在耗时任务上
加一层熔断+监控,让保护看得见
仅靠线程池内置机制还不够,需外部协同:
- 用 Sentinel 或 Resilience4j 对调用入口限流,提前拦截过载请求,不让它们到达线程池
- 暴露关键指标:活跃线程数、队列剩余容量、拒绝任务计数——接入 Prometheus + Grafana 实时看板
- 设置告警规则:例如“1 分钟内拒绝任务 > 10 次”或“队列填充率连续 5 分钟 > 90%”立即通知


















