八股文解析
线程池参数与拒绝策略实战
线程池参数与拒绝策略实战
一句话结论
- 线程池不是越大越好:CPU 密集型 ≈ 核数 +1,IO 密集型 ≈ 核数 × (1 + 平均等待/平均计算)
- 拒绝策略要匹配业务:核心请求用
CallerRunsPolicy,可丢弃用DiscardPolicy
面试标准答法
ThreadPoolExecutor 七大参数
ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 空闲线程存活时间
TimeUnit unit,
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
)执行流程:
- 核心线程未满 → 直接创建核心线程执行
- 核心线程已满 → 入队
- 队列已满 → 创建非核心线程
- 最大线程已满 → 触发拒绝策略
四种拒绝策略
| 策略 | 行为 | 适用场景 |
|---|---|---|
AbortPolicy | 抛 RejectedExecutionException | 默认,核心任务不可丢 |
CallerRunsPolicy | 由调用线程直接执行 | 减缓提交速度,保证执行 |
DiscardPolicy | 静默丢弃 | 允许丢失的监控/日志 |
DiscardOldestPolicy | 丢弃队列最老任务 | 队列积压严重时 |
队列选择
SynchronousQueue:不存储,直接交接(CachedThreadPool)LinkedBlockingQueue:无界,可能 OOM(FixedThreadPool)ArrayBlockingQueue:有界,推荐生产使用PriorityBlockingQueue:优先级调度
线程数估算
- CPU 密集型:
N_cpu + 1(如加密、压缩、算法) - IO 密集型:
N_cpu × (1 + W/C),W=等待时间,C=计算时间(如 RPC、DB、文件)
经验值:Web 服务常配 N_cpu × 2 到 N_cpu × 4,再结合压测调整。
常见追问
| 追问 | 要点 |
|---|---|
为什么阿里规范不推荐 Executors? | FixedThreadPool 和 SingleThreadPool 用无界队列,可能 OOM;CachedThreadPool 可创建 Integer.MAX_VALUE 线程 |
keepAliveTime 对核心线程生效吗? | 默认不生效,设置 allowCoreThreadTimeOut(true) 后生效 |
| 如何监控线程池? | 自定义 ThreadPoolExecutor 重写 beforeExecute / afterExecute,或接入 Micrometer/Prometheus |
面试回答模板(30 秒版)
延伸准备
- 能手写自定义线程池 + 拒绝策略(进 MQ)
- 能解释
ThreadLocal在线程池中的内存泄漏风险 - 能对比
ForkJoinPool和ThreadPoolExecutor适用场景