外观
一句话答案
四种策略:AbortPolicy(抛异常)、CallerRunsPolicy(调用者执行,推荐)、DiscardPolicy(丢弃)、DiscardOldestPolicy(丢最老)。
核心要点
四种策略:
| 策略 | 行为 | 适用场景 |
|---|---|---|
| AbortPolicy(默认) | 抛 RejectedExecutionException | 关键任务,不允许丢失 |
| CallerRunsPolicy | 由提交任务的线程执行 | 降速不丢任务(背压机制) |
| DiscardPolicy | 静默丢弃新任务 | 允许丢失的非关键任务 |
| DiscardOldestPolicy | 丢弃队列最老的任务 | 只关心最新任务 |
生产建议:
- 不要用默认的 AbortPolicy(异常容易被吞)
- 推荐 CallerRunsPolicy:自动限流,不会丢任务
- 自定义策略:记录日志 + 持久化到 MQ/DB + 告警
java
new ThreadPoolExecutor.CallerRunsPolicy()
// 或自定义:
(r, executor) -> {
log.warn("Task rejected: {}", r);
// 持久化到MQ重试
}追问与易错
追问方向:
- CallerRunsPolicy 有什么问题?
- 你会怎么自定义拒绝策略?
- 线程池不当导致过什么线上问题?
易错点:
- ❌ 默认 AbortPolicy 就好——异常容易被吞
- ❌ 拒绝策略不重要——是系统保护最后一道防线
💡 记忆锚点
线程池满了像餐厅客满:Abort 是直接在门口报警赶客(抛异常),CallerRuns 是让老板亲自端盘子(调用者线程干活,自动限流),Discard 是悄悄把新客人赶走(静默丢弃),DiscardOldest 是把等最久的人请走腾位置。生产上推荐 CallerRuns 或自定义(记日志+存 MQ 重试)。