一句话总结:
Java 的线程池就像快递站的小哥团队——人多人少灵活调,任务来了不抓瞎!
一、五种快递团队(线程池类型)
1. 固定小哥团队(FixedThreadPool)
-
特点:
- 固定数量小哥(线程),比如 5 个。
- 任务太多就排队(无界队列
LinkedBlockingQueue)。
-
适用场景:
- 长期高负载任务(如后台处理订单)。
-
风险:
- 任务队列无限增长 → 内存爆炸(OOM)!
ExecutorService pool = Executors.newFixedThreadPool(5);
2. 弹性临时工团队(CachedThreadPool)
-
特点:
- 来多少任务招多少人(线程数无上限)。
- 小哥摸鱼 60 秒就开除(空闲线程超时回收)。
-
适用场景:
- 短时高频任务(如处理 HTTP 请求)。
-
风险:
- 任务太多 → 招数万临时工 → CPU 炸裂!
ExecutorService pool = Executors.newCachedThreadPool();
3. 佛系单人团队(SingleThreadExecutor)
-
特点:
- 只雇 1 个小哥,任务严格排队执行。
-
适用场景:
- 需要顺序执行任务(如日志写入)。
-
风险:
- 和
FixedThreadPool一样,队列可能撑爆内存!
- 和
ExecutorService pool = Executors.newSingleThreadExecutor();
4. 闹钟团队(ScheduledThreadPool)
-
特点:
- 小哥们带闹钟,定时执行任务(如每天 8 点发推送)。
- 支持固定频率(
scheduleAtFixedRate)或固定延迟(scheduleWithFixedDelay)。
-
适用场景:
- 定时任务、周期性任务(如数据同步)。
ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
pool.scheduleAtFixedRate(() -> System.out.println("整点报时"), 0, 1, TimeUnit.HOURS);
5. 分工合作团队(ForkJoinPool)
-
特点:
- 小哥们会“偷任务”(工作窃取算法),忙的帮闲的。
- 适合分治任务(如大规模数据处理)。
-
适用场景:
- 递归分解任务(如归并排序、并行流计算)。
ForkJoinPool pool = new ForkJoinPool();
pool.submit(() -> {
// 使用 RecursiveTask 拆分任务
});
二、为什么不推荐用 Executors 创建线程池?
-
FixedThreadPool 和 SingleThreadExecutor:
- 使用无界队列 → 任务堆积导致 OOM。
-
CachedThreadPool:
- 线程数无上限 → 任务暴增时线程爆炸 → CPU 100%。
正确姿势:手动配置 ThreadPoolExecutor,控制核心参数!
ThreadPoolExecutor safePool = new ThreadPoolExecutor(
5, // 核心小哥数
10, // 最大小哥数(忙时招临时工)
60, TimeUnit.SECONDS, // 临时工摸鱼多久开除
new ArrayBlockingQueue<>(100), // 有界队列(容量100)
new ThreadPoolExecutor.CallerRunsPolicy() // 队列满了,让提交任务的线程自己干!
);
三、线程池参数口诀
“核心线程常驻岗,临时线程忙时上。
队列容量要设限,拒绝策略不能忘。
任务提交先看核,核满入队等帮忙。
队满再招临时工,工满只好拒任务!”
四、如何选型?
| 场景 | 推荐线程池 | 原因 |
|---|---|---|
| 高并发短任务 | CachedThreadPool | 快速响应,线程自动回收 |
| 顺序执行任务 | SingleThreadExecutor | 保证顺序性 |
| 定时/周期性任务 | ScheduledThreadPool | 内置定时功能 |
| CPU 密集型任务 | FixedThreadPool(核数=CPU核心数) | 避免过多线程争抢 CPU |
| IO 密集型任务 | 手动配置(核心数多些) | 线程等待 IO 时可处理其他任务 |
总结
“线程池,五兄弟,各有各的杀手锏。
Executors 虽方便,暗藏风险要避免。
手动配置最靠谱,参数调优保平安!”