JAVA面试-并发篇 10-为什么不推荐使用 Executors 创建线程池
·
为什么不推荐使用 Executors 创建线程池
一、文章概述
Executors 是 JDK 提供的线程池工具类,虽然使用简单,但生产环境严禁使用。其封装的线程池存在无界队列、无界线程、参数不可控三大致命隐患,极易引发 OOM 崩溃和服务雪崩。本文结合具体场景说明隐患原因,并详解 ThreadPoolExecutor 核心参数与执行逻辑。
二、三大隐患及场景举例
1. 无界队列:内存溢出 OOM
newFixedThreadPool 和 newSingleThreadExecutor 使用无界 LinkedBlockingQueue(默认容量 Integer.MAX_VALUE),任务会无限堆积。
场景:核心线程数为 1,每个任务执行 1 秒,每秒提交 100 个任务。1 分钟后队列将堆积 5940 个任务,每个任务对象约 1KB,仅队列就占用近 6MB;若持续提交,最终会耗尽堆内存触发 OOM。
2. 无界线程:CPU 耗尽 + OOM
newCachedThreadPool 的最大线程数为 Integer.MAX_VALUE,只要有任务就创建新线程。
场景:短时间内提交 1 万个任务,会立即创建 1 万个线程。每个线程默认栈内存 1MB,仅栈空间就占用 10GB;同时大量线程切换会导致 CPU 使用率飙升至 100%,服务完全卡死。
3. 参数不可控:不符合生产规范
Executors 封装的方法无法自定义核心参数:
- 无法设置有界队列容量,只能使用无界队列
- 无法自定义拒绝策略,默认直接抛异常
- 无法设置线程名称,排查问题时无法定位线程归属
- 无法调整非核心线程的空闲回收时间
三、ThreadPoolExecutor 核心参数与流程
| 参数 | 核心作用 |
|---|---|
| corePoolSize | 常驻核心线程数 |
| maximumPoolSize | 最大线程数 |
| keepAliveTime | 非核心线程空闲超时时间 |
| workQueue | 任务阻塞队列 |
| handler | 拒绝策略 |
四、核心线程 vs 非核心线程
| 类型 | 特点 |
|---|---|
| 核心线程 | 常驻线程池,不会被回收 |
| 非核心线程 | 临时创建,空闲超时自动回收 |
五、四种拒绝策略
- AbortPolicy:直接抛异常(默认)
- CallerRunsPolicy:调用者线程执行任务
- DiscardPolicy:直接丢弃当前任务
- DiscardOldestPolicy:丢弃队列最旧任务
总结
Executors 创建的线程池存在严重生产风险,必须手动使用 ThreadPoolExecutor 构建。根据业务场景合理设置核心线程数、有界队列容量和拒绝策略,才能保证服务稳定运行。
更多推荐

所有评论(0)