Java线程池是后端开发的高频知识点,不但面试常考,线上系统也广泛应用。本文将从基础讲起,结合源码与实战,一次性搞懂线程池的底层原理、使用方式和避坑指南。
我们先来看一个问题:
如果每来一个任务就创建一个线程处理,会怎样?
答:内存爆炸,CPU飙高,系统直接崩溃!
Java的核心线程池类是:ThreadPoolExecutor
它实现了Executor和ExecutorService接口。
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 非核心线程最大空闲时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory, // 线程工厂(可定制线程名)
RejectedExecutionHandler handler // 拒绝策略
)Executor
└── ExecutorService
└── AbstractExecutorService
└── ThreadPoolExecutor当你调用execute(task)时,线程池执行流程如下:
BlockingQueue
✅图示版可视化:
+------------+
task ---> | 线程池 |
+-----+------+
|
------------------------------
| core 线程未满? → 创建新线程
| 队列未满? → 入队排队
| max线程未满? → 创建非核心线程
| 否则 → 拒绝策略import java.util.concurrent.*;
public class ThreadPoolDemo {
public static void main(String[] args) throws InterruptedException {
ExecutorService pool = new ThreadPoolExecutor(
4, 8, 30L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
for (int i = 1; i <= 20; i++) {
final int taskId = i;
pool.execute(() -> {
System.out.println("任务 " + taskId + " 执行中,线程:" + Thread.currentThread().getName());
try {
Thread.sleep(1000); // 模拟任务耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
pool.shutdown();
pool.awaitTermination(1, TimeUnit.MINUTES);
System.out.println("所有任务执行完毕");
}
}Java 提供了常用线程池工厂方法:
方法 | 特点 |
|---|---|
Executors.newFixedThreadPool(n) | 固定大小线程池 |
Executors.newCachedThreadPool() | 自动扩容(线程数无上限) |
Executors.newSingleThreadExecutor() | 单线程串行执行 |
Executors.newScheduledThreadPool(n) | 定时任务线程池 |
🚫警告:生产环境推荐使用自定义 ThreadPoolExecutor,而非 Executors 工具类,因为其默认参数可能导致OOM或线程泄露。
当任务队列已满且线程数达到最大值,会触发拒绝策略:
策略 | 行为 |
|---|---|
AbortPolicy(默认) | 抛出异常 |
CallerRunsPolicy | 用调用者线程执行任务 |
DiscardPolicy | 静默丢弃任务 |
DiscardOldestPolicy | 丢弃最早排队任务,再尝试提交 |
推荐使用 CallerRunsPolicy:任务不会丢失,但会回退到调用线程执行,保证系统不雪崩。
CPU核心数 + 1(IO密集型可再高)
可通过如下方式获取线程池运行状态:
ThreadPoolExecutor executor = (ThreadPoolExecutor) pool;
System.out.println("核心线程数: " + executor.getCorePoolSize());
System.out.println("活跃线程数: " + executor.getActiveCount());
System.out.println("任务完成数: " + executor.getCompletedTaskCount());结合 Prometheus + Micrometer 可实现可视化监控!
线程池是 Java 高性能编程的核心技能,它不仅能提升系统性能,还能帮助你写出更优雅、可控的代码。
如果这篇文章帮你理清了思路,欢迎:
我们下篇文章见,记得关注哟~ 👋