阿里Java开发手册明确规定:禁止使用Executors创建线程池!为什么?因为它是OOM的定时炸弹!
一、Executors的三大陷阱
陷阱1:newFixedThreadPool - 无界队列OOM
// ❌ 危险代码
ExecutorService executor = Executors.newFixedThreadPool(10);
源码:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(
nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>() // 💣 无界队列!
);
}
问题: LinkedBlockingQueue默认容量Integer.MAX_VALUE(21亿)
场景:
ExecutorService executor = Executors.newFixedThreadPool(10);
// 疯狂提交任务
for (int i = 0; i < 1000000; i++) {
executor.submit(() -> {
Thread.sleep(10000); // 慢任务
});
}
// 队列积压100万个任务 → OOM!💥
陷阱2:newCachedThreadPool - 无限线程OOM
// ❌ 危险代码
ExecutorService executor = Executors.newCachedThreadPool();
源码:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(
0, Integer.MAX_VALUE, // 💣 最大线程数无限!
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>()
);
}
问题: 最大线程数Integer.MAX_VALUE
场景:
ExecutorService executor = Executors.newCachedThreadPool();
// 突发大量任务
for (int i = 0; i < 10000; i++) {
executor.submit(() -> {
Thread.sleep(10000);
});
}
// 创建1万个线程 → OOM!💥
陷阱3:newScheduledThreadPool - 无界队列OOM
// ❌ 危险代码
ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
源码:
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue()); // 💣 无界队列!
}
二、正确的创建方式✅
方式1:手动创建ThreadPoolExecutor(推荐)
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10, // 核心线程数
50, // 最大线程数
60L, TimeUnit.SECONDS, // 空闲线程存活时间
new ArrayBlockingQueue<>(1000), // 有界队列,容量1000
new ThreadFactoryBuilder()
.setNameFormat("业务线程池-%d")
.setDaemon(false)
.build(),
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
方式2:Spring Boot配置
@Configuration
public class ThreadPoolConfig {
@Bean("asyncExecutor")
public ThreadPoolTaskExecutor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(1000);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("async-");
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.CallerRunsPolicy()
);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
}
方式3:使用Guava ThreadFactoryBuilder
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat("worker-%d")
.setDaemon(true)
.setPriority(Thread.NORM_PRIORITY)
.setUncaughtExceptionHandler((t, e) ->
log.error("线程" + t.getName() + "异常", e)
)
.build();
ExecutorService executor = new ThreadPoolExecutor(
10, 20, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
threadFactory,
new ThreadPoolExecutor.AbortPolicy()
);
三、参数如何设置?
CPU密集型任务
int processors = Runtime.getRuntime().availableProcessors();
int corePoolSize = processors + 1;
int maxPoolSize = processors * 2;
IO密集型任务
int processors = Runtime.getRuntime().availableProcessors();
int corePoolSize = processors * 2;
int maxPoolSize = processors * 4;
混合型任务
// 根据IO等待时间比例调整
int corePoolSize = processors * (1 + IO等待时间/CPU计算时间);
四、队列选择
| 队列类型 | 容量 | 特点 | 适用场景 |
|---|---|---|---|
| ArrayBlockingQueue | 有界 | 数组实现 | 内存可控 ✅ |
| LinkedBlockingQueue | 可选 | 链表实现 | 需要指定容量 |
| SynchronousQueue | 0 | 直接交付 | CachedThreadPool |
| PriorityBlockingQueue | 无界 | 优先级 | 任务有优先级 |
| DelayQueue | 无界 | 延迟 | 定时任务 |
五、监控与告警
// 定时监控线程池状态
ScheduledExecutorService monitor = Executors.newSingleThreadScheduledExecutor();
monitor.scheduleAtFixedRate(() -> {
ThreadPoolExecutor tpe = (ThreadPoolExecutor) executor;
int activeCount = tpe.getActiveCount();
int poolSize = tpe.getPoolSize();
int queueSize = tpe.getQueue().size();
long completedTasks = tpe.getCompletedTaskCount();
log.info("线程池状态: 活跃={}, 总数={}, 队列={}, 已完成={}",
activeCount, poolSize, queueSize, completedTasks);
// 告警
if (queueSize > 800) {
alert("队列堆积: " + queueSize);
}
if (activeCount == poolSize && queueSize > 500) {
alert("线程池接近满负荷");
}
}, 10, 10, TimeUnit.SECONDS);
六、面试高频问答💯
Q: 为什么禁止用Executors?
A: 三大风险:
- newFixedThreadPool:无界队列,任务堆积OOM
- newCachedThreadPool:无限线程,线程爆炸OOM
- newScheduledThreadPool:无界队列,任务堆积OOM
Q: 线程池核心参数如何设置?
A:
- corePoolSize:CPU密集=核心数+1,IO密集=核心数*2
- maxPoolSize:CPU密集=核心数2,IO密集=核心数4
- queueCapacity:根据内存和业务设置(建议1000以内)
- keepAliveTime:60秒(根据业务调整)
Q: 如何选择队列?
A:
- 有界队列:ArrayBlockingQueue(推荐)
- 无界队列:禁止使用(OOM风险)
- 零容量:SynchronousQueue(特殊场景)
下一篇→ 活锁:比死锁更隐蔽的陷阱🔄