前言
在Java后端开发中,线程池是一个绕不开的话题。不管你是做Web开发、微服务,还是处理异步任务,都离不开它。但很多小伙伴在使用线程池时都会有这样的困惑:
"框架自带线程池挺好用的,为什么还要自定义?" "什么情况下必须自定义线程池?" "自定义线程池该怎么配置参数?"
今天这篇文章,我将从源码层面 深入剖析Java线程池的原理,对比分析框架自带线程池 和自定义线程池的区别,并通过大量实战代码帮你彻底搞懂这个知识点。
一、线程池到底是什么?
1.1 为什么需要线程池?
在正式介绍线程池之前,我们先来理解一个问题:为什么需要线程池?
假设这样一个场景:我们要处理1000个请求,每个请求需要执行一个耗时的IO操作。
不用线程池的写法:
java
public class BadExample {
public void processRequests(List<Request> requests) {
for (Request request : requests) {
// 每来一个请求就创建一个线程
new Thread(() -> {
// 处理IO操作
doIOOperation(request);
}).start();
}
}
}
这种写法会有什么问题?
| 问题 | 说明 |
|---|---|
| 线程创建销毁开销大 | 每次请求都创建新线程,1000个请求就要创建1000个线程,线程创建和销毁需要调用系统内核,非常耗时 |
| 内存占用高 | 每个线程默认占用1MB左右的栈空间,1000个线程就占用1GB内存 |
| 系统资源耗尽 | 线程数量不可控,可能创建数万线程,导致OOM(OutOfMemoryError) |
| 无法复用 | 任务执行完线程就销毁,无法复用,资源浪费严重 |
用线程池的写法:
java
public class GoodExample {
private ExecutorService executor = Executors.newFixedThreadPool(10);
public void processRequests(List<Request> requests) {
for (Request request : requests) {
// 提交任务到线程池,线程会被复用
executor.execute(() -> {
doIOOperation(request);
});
}
}
}
线程池就像一个任务加工厂:
- 核心工人数量固定(比如10个)
- 有任务就处理,没任务就待命
- 工人可以复用,不会每来一个任务就换人
- 任务太多时,有等候区排队
- 超过负荷可以扩容或者拒绝任务
1.2 线程池的核心概念
在Java中,线程池由以下核心组件构成:
css
┌─────────────────────────────────────────────────────────┐
│ 线程池 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 任务队列 │ │
│ │ [任务1] [任务2] [任务3] [任务4] ...... │ │
│ └─────────────────────────────────────────────────┘ │
│ ↓↑ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 线程池核心参数 │ │
│ │ • corePoolSize(核心线程数) │ │
│ │ • maximumPoolSize(最大线程数) │ │
│ │ • keepAliveTime(空闲线程存活时间) │ │
│ │ • unit(时间单位) │ │
│ │ • workQueue(任务队列) │ │
│ │ • threadFactory(线程工厂) │ │
│ │ • handler(拒绝策略) │ │
│ └─────────────────────────────────────────────────┘ │
│ ↓↑ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │线程1 │ │线程2 │ │线程3 │ │线程4 │ ... │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
└─────────────────────────────────────────────────────────┘
核心参数解析:
| 参数 | 含义 | 类比理解 |
|---|---|---|
corePoolSize |
核心线程数,线程池始终保持的线程数量 | 正式员工数量 |
maximumPoolSize |
最大线程数,线程池允许的最大线程数量 | 公司最大员工数(含外包) |
keepAliveTime |
空闲线程存活时间 | 临时工没活干多久被辞退 |
workQueue |
任务队列,用于存放待执行的任务 | 任务等候区 |
threadFactory |
线程工厂,用于创建新线程 | 人事部门 |
handler |
拒绝策略,当任务无法执行时的处理方式 | 任务太多时的应对方案 |
1.3 线程池的工作流程
线程池的任务处理流程可以用一张图来描述:
yaml
┌─────────────────┐
│ 有新任务提交 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 核心线程数未满? │
└────────┬────────┘
│
┌──────────────┴──────────────┐
│ Yes │ No
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ 创建新核心线程 │ │ 队列已满? │
│ 执行新任务 │ └────────┬────────┘
└─────────────────┘ │
┌─────────┴─────────┐
│ Yes │ No
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ 最大线程数未满? │ │ 进入队列等待 │
└────────┬────────┘ └─────────────────┘
│
┌──────────┴──────────┐
│ Yes │ No
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ 创建临时线程 │ │ 执行拒绝策略 │
│ 执行新任务 │ │ (抛异常/丢弃等)│
└─────────────────┘ └─────────────────┘
简化版规则:
- 先 core 满不满:任务来了,先看核心线程有没有空
- 再队列满不满:核心线程满了,看队列能不能排队
- 最后 max 满不满:队列也满了,看能不能扩容到最大线程数
- 都不行就拒绝:都满了,只能执行拒绝策略
二、Java原生线程池:Executor框架
2.1 家族图谱一览
Java的线程池体系非常完善,主要分为以下几类:
scss
java.util.concurrent.Executor(接口)
│
├── ExecutorService(接口)
│ │
│ ├── AbstractExecutorService(抽象类)
│ │ │
│ │ └── ThreadPoolExecutor(核心实现)
│ │ │
│ │ └── ScheduledThreadPoolExecutor(定时任务)
│ │
│ └── Executors(工具类,工厂方法)
│ │
│ ├── newFixedThreadPool() → 固定大小线程池
│ ├── newCachedThreadPool() → 缓存线程池
│ ├── newSingleThreadExecutor() → 单线程线程池
│ └── newScheduledThreadPool() → 定时线程池
│
└── Executors(工具类)
2.2 四种常用线程池详解
2.2.1 FixedThreadPool(固定大小线程池)
创建方式:
java
// 创建一个固定5个线程的线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
// 或者使用ThreadPoolExecutor直接创建
ExecutorService executor = new ThreadPoolExecutor(
5, // corePoolSize = 5
5, // maximumPoolSize = 5(与核心线程数相同)
0L, // keepAliveTime = 0(不需要,因为没有临时线程)
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>() // 无界队列
);
特点:
- 核心线程数 = 最大线程数,不会创建临时线程
- 使用无界队列(Integer.MAX_VALUE),理论上可以无限接收任务
- 适合CPU密集型 任务,或者任务量已知、相对平稳的场景
执行流程图示:
css
┌─────────────────┐
│ 新任务 │
└────────┬────────┘
│
▼
┌───────────────────────────────┐
│ 核心线程1 | 2 | 3 | 4 | 5 │
│ [忙] [忙] [忙] [忙] [忙] │
│ │
│ [全部忙碌,继续入队] │
└───────────────────────────────┘
│
▼
┌─────────────────┐
│ 无界队列 │
│ [任务6][任务7][任务8]...│
└─────────────────┘
实战示例:
java
public class FixedThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 1; i <= 10; i++) {
final int taskId = i;
executor.execute(() -> {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " 正在执行任务 " + taskId);
try {
// 模拟任务执行
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName + " 完成任务 " + taskId);
});
}
// 关闭线程池
executor.shutdown();
}
}
输出示例:
arduino
pool-1-thread-1 正在执行任务 1
pool-1-thread-2 正在执行任务 2
pool-1-thread-3 正在执行任务 3
pool-1-thread-1 完成任务 1
pool-1-thread-1 正在执行任务 4
pool-1-thread-2 完成任务 2
pool-1-thread-2 正在执行任务 5
...
可以看到,3个线程交替执行10个任务,复用线程,无需反复创建销毁。
2.2.2 CachedThreadPool(缓存线程池)
创建方式:
java
// 创建缓存线程池
ExecutorService executor = Executors.newCachedThreadPool();
// 等价于
new ThreadPoolExecutor(
0, // corePoolSize = 0
Integer.MAX_VALUE, // maximumPoolSize = 无穷大
60L, // keepAliveTime = 60秒
TimeUnit.SECONDS,
new SynchronousQueue<Runnable>() // 同步队列
);
特点:
- 核心线程数为0,所有线程都是临时线程
- 最大线程数无上限(理论上)
- 60秒内没有任务执行的线程会被销毁
- 使用SynchronousQueue同步队列,不存储任务
- 适合短时间大量小任务的场景
执行流程图示:
yaml
┌─────────────────┐
│ 新任务 │
└────────┬────────┘
│
▼
┌───────────────────────────────┐
│ SynchronousQueue │
│ [必须有消费者立即消费] │
└───────────────────────────────┘
│
▼
┌───────────────────────────────┐
│ 有空闲线程? │
└───────────────┬───────────────┘
│
┌────────────┴────────────┐
│ Yes │ No
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ 复用空闲线程 │ │ 创建新线程 │
│ 执行任务 │ │ 执行任务 │
└─────────────────┘ └─────────────────┘
实战示例:
java
public class CachedThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
long startTime = System.currentTimeMillis();
for (int i = 1; i <= 20; i++) {
final int taskId = i;
executor.execute(() -> {
String threadName = Thread.currentThread().getName();
System.out.println("任务 " + taskId + " -> " + threadName);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
try {
// 等待所有任务完成
executor.awaitTermination(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("总耗时:" + (endTime - startTime) + "ms");
}
}
危险提示: CachedThreadPool在任务量大时可能创建过多线程,导致OOM!
java
// 危险代码示例:模拟OOM
public class OOMDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
// 模拟无限提交任务
IntStream.range(0, Integer.MAX_VALUE).forEach(i -> {
executor.execute(() -> {
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {}
});
});
}
}
2.2.3 SingleThreadExecutor(单线程线程池)
创建方式:
java
ExecutorService executor = Executors.newSingleThreadExecutor();
// 等价于
new ThreadPoolExecutor(
1, // corePoolSize = 1
1, // maximumPoolSize = 1
0L, // keepAliveTime = 0
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>() // 无界队列
);
特点:
- 只有一个工作线程
- 所有任务串行执行
- 任务队列无界
- 保证任务执行顺序,不会出现并发问题
- 适合需要保证顺序执行的场景
实战示例:
java
public class SingleThreadExecutorDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 1; i <= 5; i++) {
final int taskId = i;
executor.execute(() -> {
System.out.println("任务 " + taskId + " 开始,线程:"
+ Thread.currentThread().getName());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务 " + taskId + " 结束");
});
}
executor.shutdown();
}
}
输出:
arduino
任务 1 开始,线程:pool-1-thread-1
任务 1 结束
任务 2 开始,线程:pool-1-thread-1
任务 2 结束
任务 3 开始,线程:pool-1-thread-1
...
2.2.4 ScheduledThreadPool(定时线程池)
创建方式:
java
ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
// 等价于
new ScheduledThreadPoolExecutor(5);
特点:
- 支持定时任务 和周期任务
- 适合需要延迟执行 或定期执行的场景
- 底层使用DelayedWorkQueue
核心方法:
java
ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
// 1. 延迟执行(只执行一次)
executor.schedule(() -> {
System.out.println("延迟3秒后执行");
}, 3, TimeUnit.SECONDS);
// 2. 固定频率执行(从上一定期任务开始时间计算)
executor.scheduleAtFixedRate(() -> {
System.out.println("每2秒执行一次(固定频率)");
}, 0, 2, TimeUnit.SECONDS);
// 3. 固定延迟执行(从上一次任务完成时间计算)
executor.scheduleWithFixedDelay(() -> {
System.out.println("每2秒执行一次(固定延迟)");
}, 0, 2, TimeUnit.SECONDS);
scheduleAtFixedRate vs scheduleWithFixedDelay 对比:
scss
假设任务执行需要3秒,周期设置为2秒:
scheduleAtFixedRate(固定频率):
|---任务1(3s)---|---任务2(3s)---|---任务3(3s)---|
0s 2s 4s 6s
⚠️ 任务会在2秒间隔后立即开始,不等待上一个任务完成!
scheduleWithFixedDelay(固定延迟):
|---任务1(3s)---|---任务2(3s)---|---任务3(3s)---|
0s 5s 10s 15s
✅ 任务会在上一个任务完成后,等待2秒再开始
2.3 线程池参数配置最佳实践
阿里巴巴Java开发手册 明确指出:禁止使用Executors创建线程池,应该使用ThreadPoolExecutor手动创建。
java
// ❌ 不推荐:使用Executors创建(阿里巴巴规范)
ExecutorService executor = Executors.newFixedThreadPool(10);
// ✅ 推荐:使用ThreadPoolExecutor手动创建
ExecutorService executor = new ThreadPoolExecutor(
10, // corePoolSize
20, // maximumPoolSize
60L, // keepAliveTime
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(200), // 有界队列
new ThreadFactory() { // 自定义线程工厂
private int count = 0;
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("my-pool-thread-" + count++);
return thread;
}
},
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);
为什么阿里巴巴要禁止Executors?
| Executors创建方式 | 问题 | 风险 |
|---|---|---|
newFixedThreadPool |
使用无界队列,可能堆积大量任务 | OOM |
newCachedThreadPool |
最大线程数无限制,可能创建过多线程 | OOM |
newSingleThreadExecutor |
使用无界队列,可能堆积大量任务 | OOM |
newScheduledThreadPool |
最大线程数无限制 | OOM |
三、ThreadPoolExecutor 源码解析
3.1 核心属性解读
ThreadPoolExecutor是Java线程池的核心实现,让我们深入源码看看:
java
public class ThreadPoolExecutor extends AbstractExecutorService {
// 原子变量:控制线程池状态和当前工作线程数
// 高3位表示状态,低29位表示线程数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 线程池的5种状态
private static final int COUNT_BITS = Integer.SIZE - 3; // 29
private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 2^29-1
// 线程池状态(高三位)
private static final int RUNNING = -1 << COUNT_BITS; // 接收新任务,处理队列任务
private static final int SHUTDOWN = 0 << COUNT_BITS; // 不接收新任务,但处理队列任务
private static final int STOP = 1 << COUNT_BITS; // 不接收新任务,不处理队列任务
private static final int TIDYING = 2 << COUNT_BITS; // 所有任务已终止
private static final int TERMINATED = 3 << COUNT_BITS; // 已完成Terminated()钩子方法
// 任务队列
private final BlockingQueue<Runnable> workQueue;
// 可重入锁:保护线程集合的访问
private final ReentrantLock mainLock = new ReentrantLock();
// 存储工作线程的集合
private final HashSet<Worker> workers = new HashSet<Worker>();
// 其他核心属性...
private final int corePoolSize; // 核心线程数
private final int maximumPoolSize; // 最大线程数
private final long keepAliveTime; // 空闲线程存活时间
private final ThreadFactory threadFactory;// 线程工厂
private final RejectedExecutionHandler rejectedExecutionHandler; // 拒绝策略
}
ctl 属性解析:
ini
ctl = 原子整数,同时保存"线程池状态"和"工作线程数"
32位整数
┌─────────┬────────────────────────────────┐
│ 高3位 │ 低29位 │
│ 状态位 │ 线程数 │
└─────────┴────────────────────────────────┘
RUNNING: 111 00000... = -1 << 29 = -536870912
SHUTDOWN: 000 00000... = 0 << 29 = 0
STOP: 001 00000... = 1 << 29 = 536870912
TIDYING: 010 00000... = 2 << 29 = 1073741824
TERMINATED: 011 00000... = 3 << 29 = 1610612736
3.2 任务提交 execute() 方法源码解析
execute()方法是线程池最核心的方法:
java
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// ====== 第一步:检查工作线程数是否小于核心线程数 ======
if (workerCountOf(c) < corePoolSize) {
// 添加新核心线程执行任务
if (addWorker(command, true))
return;
c = ctl.get();
}
// ====== 第二步:尝试将任务加入队列 ======
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
// 重新检查:如果线程池已不是RUNNING状态,移除任务
if (!isRunning(recheck) && remove(command)) {
reject(command); // 执行拒绝策略
}
// 如果工作线程数为0,创建新的核心线程(队列可能有其他任务)
else if (workerCountOf(recheck) == 0) {
addWorker(null, false);
}
}
// ====== 第三步:队列满了,尝试创建临时线程 ======
else if (!addWorker(command, false))
// ====== 第四步:都失败了,执行拒绝策略 ======
reject(command);
}
流程图解:
yaml
┌─────────────────┐
│ execute() │
└────────┬────────┘
│
▼
┌─────────────────┐
│ command == null?│
└────────┬────────┘
│
┌──────────────┴──────────────┐
│ Yes │ No
▼ ▼
┌──────────┐ ┌─────────────────┐
│ 抛异常 │ │ 读取ctl值 │
└──────────┘ └────────┬────────┘
▼
┌────────────────────────┐
│ 工作线程数 < 核心线程数 │
└────────────┬───────────┘
│
┌──────────────┴──────────────┐
│ Yes │ No
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ addWorker(task, │ │ 进入任务队列 │
│ true) │ │ workQueue.offer │
└────────┬────────┘ └────────┬────────┘
│ │
┌──────────────┴──────────────┐ │
│ Success │ Fail │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 返回,任务被 │ │ 重新获取ctl │ │ 成功? 重新检查 │
│ 核心线程执行 │ │ 继续判断 │ │ 失败? 拒绝任务 │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ 工作线程数=0? │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 创建新核心线程 │
│ 处理队列任务 │
└─────────────────┘
3.3 addWorker() 源码解析
addWorker负责创建新线程并执行任务:
java
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 检查线程池状态:
// 1. 不是RUNNING状态,不接收新任务
// 2. 是SHUTDOWN状态,但firstTask不为空或队列为空,不创建新线程
if (rs >= SHUTDOWN &&
!(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
// 检查线程数是否超限
if (wc >= (core ? corePoolSize : maximumPoolSize) ||
wc >= CAPACITY)
return false;
// CAS增加工作线程数
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get();
if (runStateOf(c) != rs)
continue retry;
}
}
// 创建Worker并启动
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive())
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
}
} finally {
mainLock.unlock();
}
t.start(); // 启动线程
workerAdded = true;
}
} finally {
if (!workerAdded) {
addWorkerFailed(w);
}
}
return workerAdded;
}
3.4 Worker 类:线程池的工作者
Worker是线程池内部的工作单元:
java
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
final Thread thread; // 执行任务的线程
Runnable firstTask; // 第一个任务(可选)
volatile long completedTasks; // 完成的任务数
Worker(Runnable firstTask) {
this.firstTask = firstTask;
// 使用线程工厂创建线程,注意this作为Runnable传入
this.thread = getThreadFactory().newThread(this);
}
// 核心方法:执行任务
public void run() {
runWorker(this);
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // 允许中断
boolean completedAbruptly = true;
try {
// 循环取任务:先取firstTask,再从队列取
while (task != null || (task = getTask()) != null) {
w.lock();
// 如果线程池STOP,确保线程被中断
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
try {
task.run(); // 执行任务
afterExecute(task, null);
} catch (RuntimeException x) {
afterExecute(task, x);
throw x;
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
}
Worker的工作流程:
scss
┌─────────────────┐
│ 线程启动 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 有firstTask? │
└────────┬────────┘
│
┌──────────────┴──────────────┐
│ Yes │ No
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ 执行firstTask │ │ 从队列取任务 │
└────────┬────────┘ │ getTask() │
│ └────────┬────────┘
│ │
└──────────────┬──────────────┘
│
▼
┌─────────────────┐
│ 任务执行中 │
│ beforeExecute() │
│ task.run() │
│ afterExecute() │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 队列还有任务? │
└────────┬────────┘
│
┌──────────────┴──────────────┐
│ Yes │ No
▼ ▼
┌─────────────┐ ┌─────────────────┐
│ 继续取任务 │ │ 线程退出/回收 │
└─────────────┘ └─────────────────┘
3.5 getTask() 源码解析
getTask()从队列获取任务:
java
private Runnable getTask() {
boolean timedOut = false; // 标识上次poll是否超时
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 检查是否需要退出线程
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// 是否需要回收线程?
// 1. 核心线程可以被回收(allowCoreThreadTimeOut)
// 2. 或者工作线程数大于核心线程数
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 从队列取任务
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take(); // 阻塞直到有任务
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
关键点:
- 如果
allowCoreThreadTimeOut=true,核心线程也会超时被回收 - 如果工作线程数 > 核心线程数,非核心线程会超时被回收
- 使用
poll()可以超时返回,take()阻塞等待
四、Spring框架中的线程池
4.1 Spring TaskExecutor
Spring定义了TaskExecutor接口,屏蔽了Java Executor的差异:
java
public interface TaskExecutor extends Executor {
void execute(Runnable task);
}
Spring内置的TaskExecutor实现:
| 实现类 | 说明 |
|---|---|
| SyncTaskExecutor | 同步执行器,在主线程执行(用于测试) |
| SimpleThreadPoolTaskExecutor | 包装Java的SimpleThreadPool |
| ThreadPoolTaskExecutor | 最常用的实现,包装ThreadPoolExecutor |
| ConcurrentTaskExecutor | 包装Java的Concurrent.ThreadPoolExecutor |
| WorkManagerTaskExecutor | 集成CommonJ WorkManager |
4.2 ThreadPoolTaskExecutor 详解
ThreadPoolTaskExecutor是Spring最常用的线程池实现:
XML配置方式:
xml
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5"/>
<property name="maxPoolSize" value="10"/>
<property name="queueCapacity" value="200"/>
<property name="threadNamePrefix" value="spring-task-"/>
<property name="keepAliveSeconds" value="60"/>
<property name="waitForTasksToCompleteOnShutdown" value="true"/>
<property name="awaitTerminationSeconds" value="60"/>
</bean>
Java配置方式(推荐):
java
@Configuration
public class AsyncConfig {
@Bean("taskExecutor")
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(5);
// 最大线程数
executor.setMaxPoolSize(10);
// 队列容量
executor.setQueueCapacity(200);
// 线程名前缀
executor.setThreadNamePrefix("spring-task-");
// 空闲线程存活时间
executor.setKeepAliveSeconds(60);
// 拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 是否等待任务完成再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 等待时间
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
}
4.3 @Async 异步执行注解
Spring的@Async注解可以让方法异步执行:
java
@Service
public class AsyncService {
// 使用自定义线程池
@Async("taskExecutor")
public void asyncMethod1() {
System.out.println("异步任务1:" + Thread.currentThread().getName());
}
// 使用默认线程池(SimpleAsyncTaskExecutor,不复用线程)
@Async
public void asyncMethod2() {
System.out.println("异步任务2:" + Thread.currentThread().getName());
}
// 带返回值
@Async("taskExecutor")
public CompletableFuture<String> asyncMethod3() {
return CompletableFuture.completedFuture("异步结果");
}
}
启动类需要开启异步支持:
java
@SpringBootApplication
@EnableAsync // 开启异步支持
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4.4 @Scheduled 定时任务
Spring的@Scheduled支持多种定时方式:
java
@Service
public class ScheduledService {
// 每5秒执行一次
@Scheduled(fixedRate = 5000)
public void fixedRateTask() {
System.out.println("fixedRate: " + new Date());
}
// 上次任务完成后,延迟3秒再执行
@Scheduled(fixedDelay = 3000)
public void fixedDelayTask() {
System.out.println("fixedDelay: " + new Date());
}
// 初始延迟2秒,然后按fixedRate执行
@Scheduled(initialDelay = 2000, fixedRate = 5000)
public void initialDelayTask() {
System.out.println("initialDelay + fixedRate: " + new Date());
}
// Cron表达式:每分钟执行一次
@Scheduled(cron = "0 * * * * ?")
public void cronTask() {
System.out.println("cron: " + new Date());
}
}
Cron表达式详解:
scss
┌───────────── 秒 (0-59)
│ ┌───────────── 分钟 (0-59)
│ │ ┌───────────── 小时 (0-23)
│ │ │ ┌───────────── 日 (1-31)
│ │ │ │ ┌───────────── 月 (1-12)
│ │ │ │ │ ┌───────────── 星期 (1-7, 1=周日)
│ │ │ │ │ │
* * * * * *
示例:
"0 0 * * * ?" 每小时整点
"0 0 10 * * ?" 每天10点
"0 30 9 1 * ?" 每月1号9:30
"0/5 * * * * ?" 每5秒
开启定时任务:
java
@SpringBootApplication
@EnableScheduling // 开启定时任务
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
五、实战:自定义线程池全攻略
5.1 为什么要自定义线程池?
| 场景 | 使用Executors | 使用自定义ThreadPoolExecutor |
|---|---|---|
| 任务数量可控 | ✅ 可以 | ✅ 可以 |
| 任务数量可能突增 | ❌ 队列无界,可能OOM | ✅ 有界队列 + 拒绝策略 |
| 需要精细化配置 | ❌ 无法配置 | ✅ 核心线程数、最大线程数、空闲时间等 |
| 需要监控线程池状态 | ❌ 无法监控 | ✅ 提供监控接口 |
| 需要自定义线程名称 | ❌ 默认名称 | ✅ 自定义ThreadFactory |
| 需要父子线程传递上下文 | ❌ 无法实现 | ✅ 可配合InheritableThreadLocal |
5.2 通用线程池配置
根据不同业务场景,给出推荐配置:
CPU密集型任务(计算、加密、压缩等)
java
/**
* CPU密集型任务配置
*
* CPU密集型特点:
* - 任务主要是计算,需要大量CPU时间
* - 线程数不宜过多,因为CPU本身是瓶颈
* - 推荐公式:CPU核心数 + 1
*
* Java获取CPU核心数:Runtime.getRuntime().availableProcessors()
*/
public class CpuIntensiveConfig {
public static ExecutorService createCpuIntensivePool() {
int cpuCount = Runtime.getRuntime().availableProcessors();
return new ThreadPoolExecutor(
cpuCount, // 核心线程数
cpuCount, // 最大线程数(CPU密集型不需要更多线程)
0L, // 不需要回收,因为没有临时线程
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(100), // 有界队列
new ThreadFactoryBuilder()
.setNameFormat("cpu-task-%d")
.build(),
new ThreadPoolExecutor.AbortPolicy()
);
}
}
IO密集型任务(网络请求、文件读写、数据库查询等)
java
/**
* IO密集型任务配置
*
* IO密集型特点:
* - 任务大部分时间在等待IO(网络、磁盘、数据库)
* - CPU经常空闲,可以创建更多线程
* - 推荐公式:CPU核心数 * 2 或 CPU核心数 / (1 - 阻塞系数)
* - 阻塞系数通常取0.8~0.9
*/
public class Io密集型Config {
public static ExecutorService createIOIntensivePool() {
int cpuCount = Runtime.getRuntime().availableProcessors();
// IO密集型:2倍CPU核心数
int corePoolSize = cpuCount * 2;
// 最大线程数可以更大
int maxPoolSize = cpuCount * 4;
return new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
60L, // 空闲线程存活时间
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(200), // 有界队列
new ThreadFactoryBuilder()
.setNameFormat("io-task-%d")
.setDaemon(false) // 设置为非守护线程
.build(),
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:调用者执行
);
}
}
混合型任务(既有CPU计算又有IO)
java
/**
* 混合型任务配置
*
* 根据实际情况调整比例
* 如果CPU计算多,增加核心线程数
* 如果IO等待多,增加队列容量
*/
public class MixedTaskConfig {
public static ExecutorService createMixedPool() {
int cpuCount = Runtime.getRuntime().availableProcessors();
return new ThreadPoolExecutor(
cpuCount + 1, // 核心线程数
cpuCount * 2, // 最大线程数
30L, // 空闲存活时间
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(500),
new ThreadFactoryBuilder()
.setNameFormat("mixed-task-%d")
.build(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
}
5.3 完整的自定义线程池工具类
java
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.*;
/**
* 线程池工具类
*
* 提供不同场景的线程池创建方法
*
* @author 苏木
*/
public class ThreadPoolUtils {
// 私有构造函数,防止实例化
private ThreadPoolUtils() {}
/**
* 创建CPU密集型线程池
*/
public static ExecutorService newCpuIntensivePool() {
int corePoolSize = Runtime.getRuntime().availableProcessors();
return new ThreadPoolExecutor(
corePoolSize,
corePoolSize,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(100),
new ThreadFactoryBuilder()
.setNameFormat("cpu-intensive-%d")
.setUncaughtExceptionHandler((t, e) -> {
System.err.println("线程 " + t.getName() + " 异常: " + e.getMessage());
})
.build(),
new ThreadPoolExecutor.AbortPolicy()
);
}
/**
* 创建IO密集型线程池
*/
public static ExecutorService newIOIntensivePool() {
int corePoolSize = Runtime.getRuntime().availableProcessors() * 2;
int maxPoolSize = Runtime.getRuntime().availableProcessors() * 4;
return new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(200),
new ThreadFactoryBuilder()
.setNameFormat("io-intensive-%d")
.setUncaughtExceptionHandler((t, e) -> {
System.err.println("线程 " + t.getName() + " 异常: " + e.getMessage());
})
.build(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
/**
* 创建带监控的线程池
*/
public static ExecutorService newMonitoredPool(
int corePoolSize,
int maxPoolSize,
int queueCapacity,
String poolName) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(queueCapacity),
new ThreadFactoryBuilder()
.setNameFormat(poolName + "-%d")
.build(),
new ThreadPoolExecutor.AbortPolicy()
);
// 添加监控任务
ScheduledExecutorService monitor = Executors.newSingleThreadScheduledExecutor(
r -> {
Thread t = new Thread(r);
t.setName(poolName + "-monitor");
t.setDaemon(true);
return t;
}
);
// 每5秒打印一次线程池状态
monitor.scheduleAtFixedRate(() -> {
printThreadPoolStatus(executor, poolName);
}, 0, 5, TimeUnit.SECONDS);
return executor;
}
/**
* 打印线程池状态
*/
public static void printThreadPoolStatus(ThreadPoolExecutor executor, String poolName) {
StringBuilder sb = new StringBuilder();
sb.append("\n========== ").append(poolName).append(" 状态 ==========\n");
sb.append(String.format(" 核心线程数: %d\n", executor.getCorePoolSize()));
sb.append(String.format(" 最大线程数: %d\n", executor.getMaximumPoolSize()));
sb.append(String.format(" 当前线程数: %d\n", executor.getPoolSize()));
sb.append(String.format(" 活跃线程数: %d\n", executor.getActiveCount()));
sb.append(String.format(" 队列大小: %d\n", executor.getQueue().size()));
sb.append(String.format(" 完成任务数: %d\n", executor.getCompletedTaskCount()));
sb.append(String.format(" 总任务数: %d\n", executor.getTaskCount()));
sb.append("===================================\n");
System.out.println(sb.toString());
}
}
5.4 线程池使用最佳实践
java
public class ThreadPoolBestPractices {
public static void main(String[] args) {
ExecutorService executor = new ThreadPoolExecutor(
5, 10, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
new ThreadFactoryBuilder()
.setNameFormat("best-practice-%d")
.build(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
try {
// ✅ 正确做法1:使用try-with-resources或手动shutdown
try (ExecutorService service = executor) {
// 提交任务
Future<String> future = executor.submit(() -> {
return doTask();
});
// ✅ 正确做法2:设置超时,避免无限等待
String result = future.get(30, TimeUnit.SECONDS);
System.out.println("任务结果: " + result);
}
// ✅ 正确做法3:使用shutdownNow尝试停止
executor.shutdownNow();
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
System.err.println("线程池未能在规定时间内终止");
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
} catch (ExecutionException | TimeoutException e) {
e.printStackTrace();
}
}
private static String doTask() {
return "Task completed";
}
}
常见错误:
java
public class ThreadPoolMistakes {
// ❌ 错误1:线程池变量定义为ExecutorService,但实际使用Executors
// 这会导致代码中到处使用newFixedThreadPool,无法统一管理
private final ExecutorService executor = Executors.newFixedThreadPool(10);
// ✅ 正确:定义为成员变量,使用统一配置
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, 10, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
new ThreadFactoryBuilder().setNameFormat("task-%d").build(),
new ThreadPoolExecutor.AbortPolicy()
);
// ❌ 错误2:任务抛出异常后未处理
public void badSubmit() {
executor.submit(() -> {
throw new RuntimeException("任务失败"); // 异常会被吞噬
});
}
// ✅ 正确:使用execute或捕获异常
public void goodSubmit() {
executor.execute(() -> {
try {
doSomething();
} catch (Exception e) {
// 处理异常
handleException(e);
}
});
}
// ❌ 错误3:忘记关闭线程池
public void forgotShutdown() {
ExecutorService executor = Executors.newFixedThreadPool(10);
// 使用完后忘记executor.shutdown()
// 导致JVM无法正常退出
}
}
六、框架线程池 vs 自定义线程池:深度对比
6.1 功能对比
| 特性 | Spring TaskExecutor | 自定义ThreadPoolExecutor |
|---|---|---|
| 参数配置 | XML/Java配置 | 完全可定制 |
| 与Spring容器集成 | ✅ 自动管理生命周期 | ❌ 需手动管理 |
| @Async异步支持 | ✅ 支持 | ❌ 需要配合其他方案 |
| @Scheduled定时支持 | ✅ 支持 | ❌ 需要配合ScheduledExecutorService |
| 监控 | 基础监控 | 可完全自定义监控 |
| 线程复用 | ✅ 支持 | ✅ 支持 |
| 拒绝策略 | 可配置 | 可配置 |
| 线程工厂 | 默认实现 | 完全可定制 |
6.2 性能对比
java
/**
* 性能测试对比
*/
public class PerformanceComparison {
public static void main(String[] args) throws Exception {
// Spring风格的线程池
ThreadPoolTaskExecutor springExecutor = new ThreadPoolTaskExecutor();
springExecutor.setCorePoolSize(10);
springExecutor.setMaxPoolSize(20);
springExecutor.setQueueCapacity(100);
springExecutor.setThreadNamePrefix("spring-");
springExecutor.initialize();
// 自定义线程池
ExecutorService customExecutor = new ThreadPoolExecutor(
10, 20, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
r -> {
Thread t = new Thread(r);
t.setName("custom-" + t.getId());
return t;
},
new ThreadPoolExecutor.AbortPolicy()
);
int taskCount = 10000;
IntStream.range(0, taskCount).forEach(i -> {
// 模拟CPU计算任务
Runnable task = () -> {
long sum = 0;
for (int j = 0; j < 1000; j++) {
sum += Math.random();
}
};
springExecutor.execute(task);
customExecutor.execute(task);
});
springExecutor.shutdown();
customExecutor.shutdown();
}
}
6.3 适用场景
yaml
┌─────────────────────────────────────────────────────────────────┐
│ 选择决策树 │
│ │
│ ┌───────────────┐ │
│ │ 你是Spring项目?│ │
│ └───────┬───────┘ │
│ │ │
│ ┌─────────────┴─────────────┐ │
│ │ Yes │ No │
│ ▼ ▼ │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ 需要@Async/@Scheduled?│ │ 需要完全自定义? │ │
│ └─────────┬───────────┘ └─────────┬───────────┘ │
│ │ │ │
│ ┌─────────┴─────────┐ │ │
│ │ Yes │ No │ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌─────────────────────┐ │
│ │ ThreadPool │ │ Spring │ │ ThreadPoolExecutor │ │
│ │ TaskExecutor│ │ SimpleAsync│ │ (完全自定义) │ │
│ │ @Async │ │ TaskExecutor│ │ │ │
│ └────────────┘ └────────────┘ └─────────────────────┘ │
│ │
│ 适用场景: │ 适用场景: │
│ • Spring Boot项目 │ • 非Spring项目 │
│ • 需要异步/定时支持 │ • 需要精细化控制 │
│ • 与Spring容器集成 │ • 特殊监控需求 │
└─────────────────────────────────────────────────────────────────┘
6.4 实战建议
Spring项目:
java
@Configuration
@EnableAsync
@EnableScheduling
public class SpringThreadPoolConfig {
/**
* 普通异步任务线程池
*/
@Bean("asyncExecutor")
public ThreadPoolTaskExecutor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(200);
executor.setThreadNamePrefix("async-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
/**
* 定时任务线程池
*/
@Bean("scheduledExecutor")
public ScheduledExecutorService scheduledExecutor() {
return Executors.newScheduledThreadPool(
5,
new ThreadFactoryBuilder()
.setNameFormat("scheduled-%d")
.build()
);
}
}
非Spring项目:
java
/**
* 非Spring环境下的线程池管理
*/
public class ThreadPoolManager {
private static volatile ThreadPoolManager instance;
private final Map<String, ExecutorService> threadPools = new ConcurrentHashMap<>();
private ThreadPoolManager() {}
public static ThreadPoolManager getInstance() {
if (instance == null) {
synchronized (ThreadPoolManager.class) {
if (instance == null) {
instance = new ThreadPoolManager();
}
}
}
return instance;
}
/**
* 注册线程池
*/
public void register(String name, ExecutorService executor) {
threadPools.put(name, executor);
}
/**
* 获取线程池
*/
public ExecutorService get(String name) {
return threadPools.get(name);
}
/**
* 关闭所有线程池
*/
public void shutdownAll() {
threadPools.values().forEach(executor -> {
executor.shutdown();
try {
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
});
}
/**
* JVM关闭时自动关闭所有线程池
*/
public void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(this::shutdownAll));
}
}
七、面试重点总结
7.1 必问知识点
Q1: 线程池的工作流程是什么?
markdown
1. 线程池收到任务
2. 判断当前工作线程数是否 < 核心线程数
- 是:创建新核心线程执行任务
- 否:进入下一步
3. 判断任务队列是否已满
- 否:将任务加入队列等待
- 是:进入下一步
4. 判断当前线程数是否 < 最大线程数
- 是:创建临时线程执行任务
- 否:执行拒绝策略
Q2: 线程池有哪几种拒绝策略?
| 策略 | 说明 |
|---|---|
| AbortPolicy | 默认策略,抛出RejectedExecutionException |
| CallerRunsPolicy | 由调用者线程执行任务 |
| DiscardPolicy | 直接丢弃任务 |
| DiscardOldestPolicy | 丢弃队列中最老的任务,然后重试 |
Q3: 如何合理配置线程池参数?
diff
- CPU密集型:核心线程数 = CPU核心数 + 1
- IO密集型:核心线程数 = CPU核心数 * 2(或更大)
- 混合型:根据实际情况调整
队列容量设置:
- 预估最大任务数
- 设置队列容量 = 最大任务数 - 核心线程数
Q4: execute()和submit()的区别?
java
// execute():用于提交不需要返回值的任务
executor.execute(() -> System.out.println("任务执行"));
// submit():用于提交需要返回值的任务,返回Future
Future<String> future = executor.submit(() -> "结果");
String result = future.get(); // 阻塞获取结果
Q5: 线程池如何实现线程复用?
scss
Worker类实现:
1. 每个Worker持有一个Thread和一个Runnable
2. Worker.run()调用runWorker()
3. runWorker()内部循环调用getTask()
4. getTask()从队列获取任务
5. 任务执行完后,继续取下一个任务
6. 没有任务时,线程阻塞等待(take())或超时等待(poll())
7.2 知识图谱
scss
┌──────────────────────────────────────────────────────────────────┐
│ Java线程池知识图谱 │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 线程池基础 │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ 为什么要 │ │ 核心参数 │ │ 工作流程 │ │ 状态转换 │ │ │
│ │ │ 用线程池 │ │ │ │ │ │ │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Executor框架 │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ Executors工具类 │ │ │
│ │ │ newFixedThreadPool / newCachedThreadPool │ │ │
│ │ │ newSingleThreadExecutor / newScheduledThreadPool │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ ThreadPoolExecutor │ │ │
│ │ │ execute() / submit() / shutdown() │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 框架集成 │ │
│ │ ┌──────────────────┐ ┌──────────────────────────────┐ │ │
│ │ │ Spring TaskExec │ │ Spring @Async/@Scheduled │ │ │
│ │ └──────────────────┘ └──────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 最佳实践 │ │
│ │ • 使用ThreadPoolExecutor而非Executors │ │
│ │ • 合理配置核心线程数和队列容量 │ │
│ │ • 选择合适的拒绝策略 │ │
│ │ • 线程池关闭和监控 │ │
│ └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
结语
这篇文章我们从线程池的基础概念出发,深入源码剖析了ThreadPoolExecutor的实现原理,对比分析了框架自带线程池和自定义线程池的区别。
核心要点回顾:
- 线程池是复用线程的机制,避免反复创建销毁线程的开销
- Java原生线程池通过Executor框架提供,Executors工具类提供了4种常用线程池
- ThreadPoolExecutor是核心实现,execute()方法遵循"核心→队列→最大→拒绝"的执行流程
- Spring TaskExecutor是对Java Executor的抽象,与Spring容器深度集成
- 自定义线程池在任务量大、需要精细化控制时是更好的选择
- 阿里巴巴规范明确禁止使用Executors创建线程池,推荐使用ThreadPoolExecutor
希望这篇文章能帮助大家彻底理解Java线程池,在实际开发中写出更优雅、更高效的并发代码!
如果对你有帮助,一键三连支持一下~
本文首发于掘金,同步更新于CSDN
更多优质内容,欢迎关注我的博客