本文是 Java 多线程与并发核心知识中的“线程池”专题,包含官方线程池分类、自定义 ThreadPoolExecutor 参数详解、工作队列选择、拒绝策略剖析、生产实践案例与高频面试题解析,适合有基础但想进一步掌握线程池底层原理的读者,内容详尽,强烈建议收藏!
线程池(ThreadPool)是一种线程复用机制。通过提前创建一定数量的线程,统一管理调度多个任务,避免频繁创建销毁线程带来的资源浪费。
✅ 总结一句话:线程池 = 控制资源 + 提升性能 + 提升并发吞吐能力
名称 | 方法 | 特点 | 使用场景 |
---|---|---|---|
单线程池 | Executors.newSingleThreadExecutor() |
只有一个线程,所有任务按顺序执行 | 日志记录、事件序列 |
固定线程池 | Executors.newFixedThreadPool(n) |
固定线程数量,任务超出排队 | 后台服务处理请求 |
缓存线程池 | Executors.newCachedThreadPool() |
无限制线程,空闲线程 60s 销毁 | 高并发短任务 |
定时线程池 | Executors.newScheduledThreadPool(n) |
延迟执行、周期执行任务 | 定时器、调度器 |
工作窃取池 | Executors.newWorkStealingPool() |
多核并行,自动分配线程 | 并行计算、大任务拆分 |
⚠️ 注意:
Executors
创建的线程池容易造成 OOM!如:CachedThreadPool + LinkedBlockingQueue 无界。强烈推荐手动创建ThreadPoolExecutor
。
ThreadPoolExecutor executor = new ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler);
参数 | 含义 |
---|---|
corePoolSize | 核心线程数,始终存活 |
maximumPoolSize | 最大线程数(任务高峰使用) |
keepAliveTime | 非核心线程空闲销毁时间 |
unit | 时间单位(秒、毫秒等) |
workQueue | 缓冲队列,存放待执行任务 |
threadFactory | 自定义线程工厂,给线程命名等 |
handler | 拒绝策略(线程池 & 队列都满了) |
execute(Runnable task)
:提交任务(无返回值)submit(Callable/Void)
:提交任务(有 Future 返回)shutdown()
:优雅关闭线程池(执行完现有任务)shutdownNow()
:立即停止,返回未执行任务列表getCorePoolSize()
:获取核心线程数量getMaximumPoolSize()
:获取最大线程数getActiveCount()
:获取当前活跃线程数getQueue().size()
:查看等待队列中任务数量prestartCoreThread()
:提前启动一个核心线程allowCoreThreadTimeOut(true)
:允许核心线程超时销毁new ThreadPoolExecutor(core, max, time, unit, workQueue);
问题:使用默认线程工厂与默认拒绝策略,灵活性差。
ThreadPoolExecutor executor = new ThreadPoolExecutor(
4, 10, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
推荐指定线程名 + 合理拒绝策略,方便排查问题
策略 | 类名 | 行为 | 适用场景 |
---|---|---|---|
AbortPolicy(默认) | ThreadPoolExecutor.AbortPolicy |
抛出异常 | 非关键任务,容忍失败 |
CallerRunsPolicy | ThreadPoolExecutor.CallerRunsPolicy |
提交线程自己执行 | 降低任务提交速度 |
DiscardPolicy | ThreadPoolExecutor.DiscardPolicy |
静默丢弃任务 | 任务非必须、丢了也没事 |
DiscardOldestPolicy | ThreadPoolExecutor.DiscardOldestPolicy |
丢最旧任务,插入当前任务 | 实时性任务,不能等 |
✅ 生产建议:使用 CallerRunsPolicy + 日志记录,避免系统挂掉
队列 | 类名 | 特点 | 说明 |
---|---|---|---|
ArrayBlockingQueue | 有界 FIFO | 固定长度,线程安全 | |
LinkedBlockingQueue | 有界/无界 | 默认无界,可能造成内存泄露 | |
SynchronousQueue | 不存任务 | 每个任务必须直接交给线程执行 | |
PriorityBlockingQueue | 带优先级 | 支持自定义优先级任务 |
ThreadFactory factory = new ThreadFactory() {
private final AtomicInteger count = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "my-thread-" + count.getAndIncrement());
}
};
CPU核数 + 1
ThreadPoolExecutor pool = new ThreadPoolExecutor(
4, 10,
60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
for (int i = 0; i < 200; i++) {
final int taskId = i;
pool.execute(() -> {
System.out.println(Thread.currentThread().getName() + " 正在执行任务:" + taskId);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
pool.shutdown();
corePoolSize
和 maximumPoolSize
有什么区别?详见上方第五节(AbortPolicy、CallerRunsPolicy、DiscardPolicy、DiscardOldestPolicy)
shutdown()
:等任务执行完再退出shutdownNow()
:立即终止,返回未执行任务列表shutdown() + awaitTermination()
配合–