总体设计

ThreadPoolExecutor实现的顶层接口是Executor,顶层接口Executor提供了一种思想:将任务提交和任务执行进行解耦。用户无需关注如何创建线程,如何调度线程来执行任务,用户只需提供Runnable对象,将任务的运行逻辑提交到执行器(Executor)中,由Executor框架完成线程的调配和任务的执行部分。ExecutorService接口增加了一些能力:(1)扩充执行任务的能力,补充可以为一个或一批异步任务生成Future的方法;(2)提供了管控线程池的方法,比如停止线程池的运行。AbstractExecutorService则是上层的抽象类,将执行任务的流程串联了起来,保证下层的实现只需关注一个执行任务的方法即可。最下层的实现类ThreadPoolExecutor实现最复杂的运行部分,ThreadPoolExecutor将会一方面维护自身的生命周期,另一方面同时管理线程和任务,使两者良好的结合从而执行并行任务。
线程池的核心类:ThreadPoolExecutor
Java 提供的线程池主要通过 java.util.concurrent.ThreadPoolExecutor 实现。
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数(常驻)
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 非核心线程的存活时间
TimeUnit unit, // 上面参数的单位
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory, // 线程工厂(创建线程的方式)
RejectedExecutionHandler handler // 拒绝策略
)
线程池参数详解
| 参数 | 说明 |
|---|---|
| corePoolSize | 核心线程数,线程池中始终保留的线程数量。 |
| maximumPoolSize | 最大线程数。线程池能创建的最大线程数(包括核心线程)。 |
| keepAliveTime | 非核心线程的空闲存活时间。超过这个时间会被销毁。 |
| unit | 存活时间单位,如 TimeUnit.SECONDS。 |
| workQueue | 任务缓存队列(如 ArrayBlockingQueue、LinkedBlockingQueue)。 |
| threadFactory | 自定义线程创建方式,可设置线程名、守护线程等。 |
| handler | 拒绝策略,线程池已满时的处理方式。 |
任务执行流程

- 若线程数 < corePoolSize → 创建新线程执行任务
- 若线程数 ≥ corePoolSize → 放入队列
- 若队列满且线程数 < maximumPoolSize → 创建新线程执行任务
- 若线程数 ≥ maximumPoolSize 且队列也满 → 触发拒绝策略
常见线程池拒绝策略(RejectedExecutionHandler)
| 策略 | 含义 |
|---|---|
| AbortPolicy | 默认策略,抛出 RejectedExecutionException 异常。 |
| CallerRunsPolicy | 谁提交谁执行(任务回退给主线程)。 |
| DiscardPolicy | 直接丢弃任务,不抛异常。 |
| DiscardOldestPolicy | 丢弃队列最旧的任务,尝试执行当前任务。 |
常用线程池队列(BlockingQueue)
| 队列类型 | 特点 |
|---|---|
| ArrayBlockingQueue | 有界,数组实现,必须设置容量,适合固定大小任务量 |
| LinkedBlockingQueue | 可设容量(默认无限),链表实现,适合任务突发 |
| SynchronousQueue | 不缓存任务,直接传递给线程,适合高并发、立即处理任务 |
如何创建线程池?
推荐:使用 ThreadPoolExecutor,避免 Executors 工厂方法(不推荐)
ExecutorService threadPool = new ThreadPoolExecutor(
2, 5,
10, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
不推荐的 Executors(会导致OOM):
Executors.newFixedThreadPool(10); // 队列无界
Executors.newCachedThreadPool(); // 线程无限
Executors.newSingleThreadExecutor(); // 只有一个线程
线程池使用示例
public class ThreadPoolDemo {
public static void main(String[] args) {
ExecutorService pool = new ThreadPoolExecutor(
2, 4,
10, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
for (int i = 0; i < 10; i++) {
final int taskId = i;
pool.execute(() -> {
System.out.println("任务 " + taskId + " 执行线程: " + Thread.currentThread().getName());
});
}
pool.shutdown(); // 关闭线程池
}
}
阿里巴巴线程池规范(强烈建议背熟)
使用 ThreadPoolExecutor 自定义线程池,禁止使用 Executors 提供的默认线程池,原因是:
FixedThreadPool和SingleThreadPool使用的是无界队列,可能导致 OOM;CachedThreadPool使用的是无界线程数量,也可能 OOM;- 推荐设置合理
队列大小和最大线程数;
Executors
Executors 是 Java 提供的线程池工厂工具类,位于 java.util.concurrent.Executors 包中,它提供了一些快速创建线程池、定时任务线程池、单线程执行器的方法,使用简单,但也有一些坑(如无界队列、OOM 等问题)。
Executors 常用方法总览
| 方法名 | 描述 | 推荐程度 |
|---|---|---|
| newFixedThreadPool(int nThreads) | 固定线程数线程池 | ❌ 不推荐(使用无界队列) |
| newCachedThreadPool() | 缓存线程池,线程数不限制 | ❌ 不推荐(线程数无界) |
| newSingleThreadExecutor() | 单线程线程池 | ❌ 不推荐(无界队列) |
| newScheduledThreadPool(int corePoolSize) | 支持定时/周期执行的线程池 | ✅ 合理使用 |
| newSingleThreadScheduledExecutor() | 单线程定时线程池 | ✅ 可用于简单定时任务 |
| newWorkStealingPool() (Java 8+) | ForkJoinPool 支持的多任务窃取线程池 | ✅ 特定并行任务 |
| callable(Runnable task, V result) | 把 Runnable 转为 Callable | ✅ 工具方法 |
| unconfigurableExecutorService(…) | 包装不可配置的线程池 | ✅ 安全场景用 |
| privilegedThreadFactory() | 获取当前线程上下文权限的 ThreadFactory | ✅ 高安全场景 |
| defaultThreadFactory() | 默认线程工厂(可用于手动 ThreadPoolExecutor) | ✅ 常用 |
重点方法说明
1. newFixedThreadPool(int nThreads)
ExecutorService pool = Executors.newFixedThreadPool(5);
- 特点:线程数固定,超出部分任务排队执行
- 使用:适合任务量固定、不会突发堆积的场景
- ⚠️ 问题:使用的是无界队列,易造成内存堆积 ➜ ❌不推荐
2. newCachedThreadPool()
ExecutorService pool = Executors.newCachedThreadPool();
- 特点:线程数量无限制(Integer.MAX_VALUE)
- 使用:适合大量、短周期的轻量任务
- ⚠️ 问题:线程无限增长,易 OOM ➜ ❌不推荐
3. newSingleThreadExecutor()
ExecutorService pool = Executors.newSingleThreadExecutor();
- 特点:只有一个线程,串行执行任务
- 使用:任务必须顺序执行场景
- ⚠️ 问题:队列无界,线程挂了会自动创建新线程,可能隐藏问题 ➜ ❌不推荐用于生产高并发
4. newScheduledThreadPool(int corePoolSize)
ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
- 特点:支持定时、周期性任务,基于
ScheduledThreadPoolExecutor - 使用:定时任务(如日志归档、缓存刷新)
- ✅ 推荐使用,但建议配合
ThreadFactory+ 拒绝策略显式构造更安全
5. newWorkStealingPool()
ExecutorService pool = Executors.newWorkStealingPool(); // Java 8+
✅ 高性能,但不适合高并发请求处理,且无法精细控制线程池参数
特点:基于 ForkJoinPool,自动按 CPU 核心数创建工作线程
使用:适合并行分治任务(如大数据分片处理)
推荐做法(线程池最佳实践)
阿里巴巴 Java 开发手册强烈建议不要使用 Executors,而是手动构造:
ThreadPoolExecutor pool = new ThreadPoolExecutor(
10, 20,
60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(200),
Executors.defaultThreadFactory(), // 可替换为自定义命名工厂
new ThreadPoolExecutor.CallerRunsPolicy()
);
拓展方法
| 方法 | 说明 |
|---|---|
| Executors.callable(Runnable task) | 把 Runnable 包装成 Callable(返回 null) |
| Executors.defaultThreadFactory() | 返回默认线程工厂,线程名如:pool-1-thread-1 |
| Executors.privilegedThreadFactory() | 创建带当前 AccessControlContext 的线程 |
| Executors.unconfigurableExecutorService() | 包装线程池,不允许调用配置方法(如 shutdownNow) |
总结:Executors 方法使用建议
| 方法 | 是否推荐 | 说明 |
|---|---|---|
| newFixedThreadPool | ❌ | 无界队列风险 |
| newCachedThreadPool | ❌ | 无界线程数风险 |
| newSingleThreadExecutor | ❌ | 无界队列、线程替换隐藏问题 |
| newScheduledThreadPool | ✅ | 合理控制线程数 |
| newWorkStealingPool | ✅ | 高吞吐并行计算 |
| 自定义 ThreadPoolExecutor | ✅强烈推荐 | 可精细控制每个参数,安全、灵活 |
ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor 是 Java 中专门用于执行定时任务和周期任务的线程池,它比 Timer 更强大、更安全,是企业级定时任务的首选方案。
ScheduledThreadPoolExecutor 是什么?
ScheduledThreadPoolExecutor 是一个线程池,支持以下几种定时任务调度:
| 调度类型 | 描述 |
|---|---|
| 延迟执行 | 延迟固定时间后执行一次任务 |
| 周期执行(固定速率) | 每隔固定时间开始执行(忽略任务执行时长) |
| 周期执行(固定延迟) | 每次任务执行完后,延迟固定时间再开始下一次 |
它是 Executors.newScheduledThreadPool(int corePoolSize) 的底层实现类,继承自 ThreadPoolExecutor。

创建线程池的方式
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
等价于:
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(
2,
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
常用方法介绍
1. schedule(Runnable command, long delay, TimeUnit unit)
延迟固定时间后执行一次
scheduler.schedule(() -> {
System.out.println("延迟 3 秒后执行一次任务");
}, 3, TimeUnit.SECONDS);
2. scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
周期执行(固定速率):每隔 period 时间触发一次任务,不管任务执行多久
scheduler.scheduleAtFixedRate(() -> {
System.out.println("每 5 秒执行一次,固定速率");
}, 1, 5, TimeUnit.SECONDS);
✅ 适合:定时轮询任务(比如定时监控、健康检查)
⚠️ 注意:如果任务执行超过周期,会出现任务并发执行重叠
3. scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
周期执行(固定延迟):每次任务执行完之后,等 delay 时间再执行下一次
scheduler.scheduleWithFixedDelay(() -> {
System.out.println("每次执行完后再等 5 秒执行");
}, 1, 5, TimeUnit.SECONDS);
✅ 适合:任务耗时不固定、希望每次之间有固定“间隔”
含义和区别:
| 方法 | 重复? | 延迟/周期点 | 执行时机 | 并发执行 |
|---|---|---|---|---|
| schedule(Runnable, delay) | 否(一次性) | 延迟 delay 后执行一次 | 不管任务执行多长时间,到达延迟点就执行一次 | 不会重复,也不存在并发问题 |
| scheduleAtFixedRate(Runnable, initialDelay, period) | 是(固定速率) | 以调度开始时间为基准,每隔 period 安排一次 | 上一次开始时间 + period 到点就触发 | 不会并发执行(内部串行),但如果执行慢于 period,会“立即”补跑 |
| scheduleWithFixedDelay(Runnable, initialDelay, delay) | 是(固定延迟) | 以上一次结束时间为基准,结束后再延迟 delay | 上一次完成时间 + delay 到点才触发 | 同样不并发执行 |
与 Timer 的区别(为什么用 ScheduledThreadPoolExecutor)
| 比较点 | Timer | ScheduledThreadPoolExecutor |
|---|---|---|
| 错误隔离 | ❌ 一个任务出异常会终止所有任务 | ✅ 一个任务异常不影响其他任务 |
| 并发支持 | ❌ 单线程 | ✅ 多线程 |
| 精度 | 一般 | 更精确 |
| 线程管理 | ❌ 不支持 | ✅ 支持线程回收、拒绝策略等 |
✅ 所以:推荐使用 ScheduledThreadPoolExecutor 替代 Timer
推荐封装方式(更安全、更灵活)
ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(
4,
new BasicThreadFactory.Builder()
.namingPattern("scheduled-task-%d")
.daemon(true)
.build(),
new ThreadPoolExecutor.AbortPolicy()
);
BasicThreadFactory是来自commons-lang3的工具类,可设置线程名、是否守护线程- 可结合监控系统收集执行时间、失败次数等
注意事项
| 问题 | 建议 |
|---|---|
| 任务执行时间过长 | 建议使用 scheduleWithFixedDelay 避免任务重叠 |
| 出现异常未捕获 | 用 try-catch 包裹任务逻辑,避免线程退出 |
| 执行慢造成堆积 | 可使用 ScheduledExecutorService.shutdownNow() 停止并清理 |
| 定时任务过多 | 拆分多个线程池,按业务划分执行优先级 |
实战示例:每晚 2 点定时执行
public class DailyTask {
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable task = () -> {
System.out.println("执行每日任务:" + LocalDateTime.now());
};
long initialDelay = computeInitialDelay(); // 计算当前时间到 2 点的间隔
long period = 24 * 60 * 60; // 每 24 小时执行一次
scheduler.scheduleAtFixedRate(task, initialDelay, period, TimeUnit.SECONDS);
}
private static long computeInitialDelay() {
LocalDateTime now = LocalDateTime.now();
LocalDateTime nextRun = now.withHour(2).withMinute(0).withSecond(0);
if (now.compareTo(nextRun) > 0) {
nextRun = nextRun.plusDays(1);
}
return Duration.between(now, nextRun).getSeconds();
}
}

