深浅模式
ThreadPool
更新: 3/4/2026 字数: 0 字
Java 并发包(java.util.concurrent)中,Executors 提供了 5 种常用的内置线程池,所有线程池底层均基于 ThreadPoolExecutor(除 ForkJoinPool 外)实现,只是参数配置不同。
线程池是一种生产者 - 消费者模式
示例代码
java
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class MyThreadPool {
// 利用阻塞队列实现生产者-消费者模式
BlockingQueue<Runnable> workQueue;
// 保存内部工作线程
List<WorkerThread> threads = new ArrayList<>();
// 构造方法
MyThreadPool(int poolSize, BlockingQueue<Runnable> workQueue) {
this.workQueue = workQueue;
// 创建工作线程
for (int idx = 0; idx < poolSize; idx++) {
WorkerThread work = new WorkerThread();
work.start();
threads.add(work);
}
}
// 提交任务
void execute(Runnable command) {
try {
workQueue.put(command);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
// 工作线程负责消费任务,并执行任务
class WorkerThread extends Thread {
public void run() {
// 循环取任务并执行
while (true) {
try {
Runnable task = workQueue.take();
task.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
static void main() {
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(2);
MyThreadPool pool = new MyThreadPool(10, workQueue);
for (int i = 0; i < 100; i++) {
pool.execute(() -> {
System.out.println("hello" + UUID.randomUUID().toString());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
}
}
}内置线程池分类(核心 6 种)
1. 固定线程池(FixedThreadPool)
核心代码 & 参数
java
// 创建方式
ExecutorService executor = Executors.newFixedThreadPool(int nThreads);
// 底层实现(简化)
new ThreadPoolExecutor(
nThreads, // 核心线程数 = 最大线程数
nThreads, // 最大线程数
0L, // 非核心线程存活时间(0,无意义)
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>() // 无界工作队列
);核心特性
- 线程数固定,核心线程数 = 最大线程数,无临时线程
- 任务队列是无界的 LinkedBlockingQueue,超出线程数的任务全部入队等待
- 核心线程不会自动销毁,即使空闲也会一直存活(除非线程池关闭)
适用场景
- CPU 密集型任务(如计算、排序),线程数建议设为 CPU 核心数 + 1
- 任务数可控、执行时间稳定的场景(避免无界队列导致内存溢出)
2. 缓存线程池(CachedThreadPool)
核心代码 & 参数
java
// 创建方式
ExecutorService executor = Executors.newCachedThreadPool();
// 底层实现(简化)
new ThreadPoolExecutor(
0, // 核心线程数 = 0
Integer.MAX_VALUE, // 最大线程数(理论无限)
60L, // 临时线程空闲 60 秒后销毁
TimeUnit.SECONDS,
new SynchronousQueue<Runnable>() // 同步队列(无容量,任务直接移交)
);核心特性
- 无核心线程,全部是临时线程,线程数可动态扩展(理论上无上限)
- 任务队列是 SynchronousQueue(同步队列),无存储能力,提交的任务必须有线程立即接收,否则创建新线程
- 空闲线程超过 60 秒自动销毁,避免资源浪费
适用场景
- IO 密集型任务(如网络请求、文件读写),任务执行时间短、数量波动大
- 需快速处理大量短期任务的场景(如临时批量处理)
风险
若任务提交速度远大于处理速度,会创建大量线程,可能导致 OutOfMemoryError(线程数过多)。
3. 单线程线程池(SingleThreadExecutor)
核心代码 & 参数
java
// 创建方式
ExecutorService executor = Executors.newSingleThreadExecutor();
// 底层实现(简化)
new ThreadPoolExecutor(
1, // 核心线程数 = 1
1, // 最大线程数 = 1
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>() // 无界队列
);核心特性
- 只有 1 个核心线程,所有任务串行执行
- 若唯一线程异常终止,会自动创建新线程替代,保证任务持续执行
- 任务队列无界,任务按提交顺序执行
适用场景
- 需保证任务按顺序执行的场景(如日志写入、订单处理)
- 需单线程处理任务,但希望线程异常后自动恢复的场景(优于手动创建单线程)
4. 定时线程池(ScheduledThreadPoolExecutor)
核心代码 & 参数
java
// 创建方式
ScheduledExecutorService executor = Executors.newScheduledThreadPool(int corePoolSize);
// 底层实现:继承 ThreadPoolExecutor,扩展定时逻辑
new ScheduledThreadPoolExecutor(
corePoolSize, // 核心线程数
// 最大线程数=Integer.MAX_VALUE,任务队列=DelayedWorkQueue(延迟队列)
);核心特性
- 支持延迟执行、周期性执行任务
- 底层队列是 DelayedWorkQueue(延迟队列),按任务到期时间排序
- 核心线程数固定,临时线程数无上限(空闲 10 秒后销毁)
核心 API
java
// 延迟 delay 时间后执行一次
executor.schedule(Runnable command, long delay, TimeUnit unit);
// 延迟 initialDelay 后,每隔 period 时间执行一次(固定频率)
executor.scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);
// 上一次任务执行完后,隔 delay 时间执行下一次(固定间隔)
executor.scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);适用场景
- 定时任务(如定时备份、定时清理缓存)
- 周期性任务(如心跳检测、数据同步)
5. 单线程定时线程池(SingleThreadScheduledExecutor)
核心代码
java
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();核心特性
- 是 ScheduledThreadPoolExecutor 的单线程版本
- 所有定时 / 周期性任务串行执行,保证顺序
- 线程异常终止时自动创建新线程
适用场景
- 需串行执行的定时任务(如单线程处理定时消息)
6. 分叉 / 合并线程池(ForkJoinPool)
核心代码
java
// JDK8+ 推荐方式(获取公共池)
ForkJoinPool pool = ForkJoinPool.commonPool();
// 自定义线程数
ForkJoinPool pool = new ForkJoinPool(int parallelism);核心特性
- 基于「分治思想」设计,适用于可拆分的大任务(如大数据量计算)
- 线程数默认等于 CPU 核心数,支持工作窃取(Work Stealing):空闲线程从繁忙线程的队列中窃取任务执行,提升效率
- 底层基于 ForkJoinTask(可拆分 / 合并的任务)
适用场景
- 大数据量并行计算(如数组求和、排序、文件遍历)
- 任务可拆分为多个子任务,且子任务可独立执行的场景
线程池对比表
| 线程池类型 | 核心线程数 | 最大线程数 | 任务队列 | 核心特性 | 适用场景 |
|---|---|---|---|---|---|
| FixedThreadPool | 自定义 | = 核心线程数 | LinkedBlockingQueue(无界) | 线程数固定,串行排队 | CPU 密集型、任务数可控 |
| CachedThreadPool | 0 | Integer.MAX_VALUE | SynchronousQueue(同步) | 动态扩缩容,无核心线程 | IO 密集型、短期任务 |
| SingleThreadExecutor | 1 | 1 | LinkedBlockingQueue(无界) | 单线程串行执行,自动恢复 | 任务需顺序执行 |
| ScheduledThreadPool | 自定义 | Integer.MAX_VALUE | DelayedWorkQueue(延迟) | 支持延迟 / 周期性执行 | 定时 / 周期性任务 |
| SingleThreadScheduledExecutor | 1 | 1 | DelayedWorkQueue(延迟) | 单线程定时执行 | 串行定时任务 |
| ForkJoinPool | CPU 核心数 | CPU 核心数 | 工作窃取队列 | 分治 + 工作窃取,并行计算 | 大数据量可拆分任务 |
使用注意事项
- 避免使用无界队列的线程池(FixedThreadPool/SingleThreadExecutor):若任务提交速度远大于处理速度,无界队列会导致内存溢出(OOM)
- CachedThreadPool 慎用:极端情况下会创建大量线程,导致系统资源耗尽
- 优先自定义 ThreadPoolExecutor:内置线程池参数固定,实际开发中建议根据业务场景自定义核心线程数、队列、拒绝策略
- ForkJoinPool 适配场景:仅适用于可拆分的任务,普通任务使用反而增加开销
总结
- 核心分类:Java 内置线程池主要包括固定、缓存、单线程、定时、分叉合并 5 类(单线程定时是定时线程池的特例)
- 底层统一:除 ForkJoinPool 外,其余均基于 ThreadPoolExecutor,仅参数配置不同
- 选型原则:根据任务类型(CPU/IO 密集)、执行方式(串行 / 并行)、调度需求(定时 / 即时)选择对应线程池
- 生产建议:优先自定义 ThreadPoolExecutor,避免内置线程池的参数固化问题
