ExecutorService线程池原理
ExecutorService 是 Java 并发包(java.util.concurrent)中用于管理和调度线程池的核心接口,它屏蔽了线程的创建、销毁和调度细节,使开发者专注于“任务”本身。下面从整体架构、核心原理、关键实现类、任务执行流程、线程复用与生命周期几个方面系统讲解。
一、ExecutorService 的整体架构
Executor(顶层接口)
|
+-- ExecutorService(扩展接口)
|
+-- AbstractExecutorService(抽象实现)
|
+-- ThreadPoolExecutor(最常用实现)
|
+-- ScheduledThreadPoolExecutor(定时任务)
核心接口说明
- Executor:只定义一个方法
execute(Runnable) - ExecutorService:在 Executor 基础上增加了
- 任务提交(
submit) - 线程池关闭(
shutdown/shutdownNow) - 批量任务执行(
invokeAll/invokeAny)
- 任务提交(
二、ThreadPoolExecutor 的核心原理
1️⃣ 构造方法(核心)
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler
)
参数含义
| 参数 | 含义 |
|---|---|
| corePoolSize | 核心线程数 |
| maximumPoolSize | 最大线程数 |
| keepAliveTime | 非核心线程空闲回收时间 |
| workQueue | 任务等待队列 |
| threadFactory | 线程工厂 |
| handler | 拒绝策略 |
三、线程池的任务执行流程(重点)
当一个任务被提交(execute 或 submit)时,流程如下:
✅ 执行流程图(逻辑)
提交任务
|
v
1. 核心线程是否已满?
├─ 否 → 创建核心线程执行
└─ 是 ↓
2. 工作队列是否已满?
├─ 否 → 放入队列等待
└─ 是 ↓
3. 线程数是否 < maximumPoolSize?
├─ 是 → 创建非核心线程执行
└─ 否 ↓
4. 执行拒绝策略
四、线程是如何被“复用”的(核心原理)
关键点:线程不会执行完一个任务就结束
线程池中的线程大致逻辑如下(简化版):
while (task != null || (task = getTask()) != null) {
task.run();
}
核心机制
- 线程从 阻塞队列中获取任务
- 如果队列为空:
- 核心线程:阻塞等待
- 非核心线程:超时等待,超时后销毁
✅ 线程复用 = 一个线程执行多个任务
五、核心线程 vs 非核心线程
| 类型 | 是否常驻 | 回收条件 |
|---|---|---|
| 核心线程 | 是 | 默认不回收(可配置) |
| 非核心线程 | 否 | 空闲超过 keepAliveTime |
核心线程即使空闲,也不会被回收(除非调用
allowCoreThreadTimeOut(true))
六、任务队列(BlockingQueue)
常见队列类型:
| 队列 | 特点 |
|---|---|
| LinkedBlockingQueue | 无界(默认 Integer.MAX_VALUE) |
| ArrayBlockingQueue | 有界 |
| SynchronousQueue | 不存储任务,直接交付 |
| PriorityBlockingQueue | 支持优先级 |
队列的影响
- 无界队列:不会创建非核心线程
- 有界队列:更容易触发线程扩容和拒绝策略
七、拒绝策略(RejectedExecutionHandler)
当线程池和队列都满时触发:
| 策略 | 行为 |
|---|---|
| AbortPolicy(默认) | 抛异常 |
| CallerRunsPolicy | 调用者线程执行 |
| DiscardPolicy | 直接丢弃 |
| DiscardOldestPolicy | 丢弃最老任务 |
八、ExecutorService 中的 submit 与 execute 区别
| 方法 | 返回值 | 是否支持 Callable |
|---|---|---|
| execute | 无 | 否 |
| submit | Future | 是 |
Future future = executor.submit(() -> "OK");
String result = future.get();
九、线程池的生命周期
线程池状态(内部用 ctl 变量表示):
RUNNING → SHUTDOWN → STOP → TIDYING → TERMINATED
关闭方法
shutdown():不再接受新任务,执行完已有任务shutdownNow():尝试中断正在执行的任务
十、常见的 Executors 工厂方法(底层仍是 ThreadPoolExecutor)
| 方法 | 特点 |
|---|---|
| newFixedThreadPool | 固定线程数 |
| newCachedThreadPool | 线程可无限增长 |
| newSingleThreadExecutor | 单线程 |
| newScheduledThreadPool | 定时任务 |
⚠️ 生产环境不推荐直接使用 Executors,原因:
- 队列无界
- 线程数不可控
- 容易 OOM
✅ 推荐使用 ThreadPoolExecutor 手动配置
十一、一句话总结
ExecutorService 线程池的本质是:用少量线程 + 阻塞队列 + 任务复用机制,避免频繁创建/销毁线程,提高系统性能和资源利用率。
如果你愿意,我可以:
- 画一张更直观的流程图
- 结合源码逐行讲解
execute()方法 - 用实际业务场景解释如何合理配置线程池参数