Java线程池是后端开发的高频知识点,不但面试常考,线上系统也广泛应用。本文将从基础讲起,结合源码与实战,一次性搞懂线程池的底层原理、使用方式和避坑指南。
🧩一、为什么要使用线程池?我们先来看一个问题:
如果每来一个任务就创建一个线程处理,会怎样?
答:内存爆炸,CPU飙高,系统直接崩溃!
✅线程池的好处: 避免频繁创建/销毁线程,节省资源
限制最大线程数,防止系统崩溃
可复用线程,提升吞吐量
支持定时任务、延迟执行等高级功能
提供任务队列、拒绝策略,灵活可控
🔍二、Java线程池类图结构(看懂你就赢了)Java的核心线程池类是:ThreadPoolExecutor
它实现了Executor和ExecutorService接口。
核心构造器如下:代码语言:javascript复制public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 非核心线程最大空闲时间
TimeUnit unit, // 时间单位
BlockingQueue
ThreadFactory threadFactory, // 线程工厂(可定制线程名)
RejectedExecutionHandler handler // 拒绝策略
)源码类图结构图示(概念理解):代码语言:javascript复制Executor
└── ExecutorService
└── AbstractExecutorService
└── ThreadPoolExecutor🎮三、工作流程图解(超清晰)当你调用execute(task)时,线程池执行流程如下:
当前运行线程数 < corePoolSize → 创建核心线程执行任务
否则任务入队到BlockingQueue
若队列满,且线程数 < maxPoolSize → 创建非核心线程执行任务
否则 → 触发拒绝策略!
✅图示版可视化:
代码语言:javascript复制 +------------+
task ---> | 线程池 |
+-----+------+
|
------------------------------
| core 线程未满? → 创建新线程
| 队列未满? → 入队排队
| max线程未满? → 创建非核心线程
| 否则 → 拒绝策略🧪四、线程池使用实战案例✅场景:提交20个耗时任务,线程池批量并发处理代码语言:javascript复制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("所有任务执行完毕");
}
}📦五、内置线程池工具类:Executors简介Java 提供了常用线程池工厂方法:
方法
特点
Executors.newFixedThreadPool(n)
固定大小线程池
Executors.newCachedThreadPool()
自动扩容(线程数无上限)
Executors.newSingleThreadExecutor()
单线程串行执行
Executors.newScheduledThreadPool(n)
定时任务线程池
🚫警告:生产环境推荐使用自定义 ThreadPoolExecutor,而非 Executors 工具类,因为其默认参数可能导致OOM或线程泄露。
⛔六、拒绝策略详解(重点)当任务队列已满且线程数达到最大值,会触发拒绝策略:
策略
行为
AbortPolicy(默认)
抛出异常
CallerRunsPolicy
用调用者线程执行任务
DiscardPolicy
静默丢弃任务
DiscardOldestPolicy
丢弃最早排队任务,再尝试提交
推荐使用 CallerRunsPolicy:任务不会丢失,但会回退到调用线程执行,保证系统不雪崩。
🧯七、线程池最佳实践建议 设置合理核心线程数:一般为 CPU核心数 + 1(IO密集型可再高)
尽量使用有界队列:防止任务无限堆积导致OOM
自定义线程工厂:方便排查问题,如设置线程名
拒绝策略要合理选择:不能静默丢任务
任务尽量短小精悍:避免长期占用线程
💡八、生产环境常见用法场景 秒杀系统中异步落库
短信/邮件发送任务
导出Excel、PDF后台生成
大批量数据分页并发处理
定时调度器任务线程池
🎁九、线程池监控指标(高级玩法)可通过如下方式获取线程池运行状态:
代码语言:javascript复制ThreadPoolExecutor executor = (ThreadPoolExecutor) pool;
System.out.println("核心线程数: " + executor.getCorePoolSize());
System.out.println("活跃线程数: " + executor.getActiveCount());
System.out.println("任务完成数: " + executor.getCompletedTaskCount());结合 Prometheus + Micrometer 可实现可视化监控!
❤️十、总结 & 点赞收藏支持一下!线程池是 Java 高性能编程的核心技能,它不仅能提升系统性能,还能帮助你写出更优雅、可控的代码。
如果这篇文章帮你理清了思路,欢迎:
点个 赞 👍鼓励一下我
点个 收藏 ⭐ 防止下次找不到
留个 评论 💬 交流你在项目中遇到的问题或心得
我们下篇文章见,记得关注哟~ 👋