1. 什么是线程池?
线程池(Thread Pool) 是 Java 并发编程中的一种优化机制,它通过 复用线程 来减少线程创建与销毁的开销,提高程序的执行效率,适用于 高并发任务处理。
线程池的核心优势
- 降低资源消耗:复用线程,避免频繁创建和销毁。
- 提高响应速度:任务到达时可立即执行,无需等待新线程创建。
- 控制并发量:通过线程池大小限制线程数量,防止系统资源耗尽。
- 提供管理能力:可设定 任务队列、超时策略、拒绝策略 等。
2. 线程池的核心参数
Java 线程池由 ThreadPoolExecutor
管理,其构造函数包含以下核心参数:
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 非核心线程存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
) {
...
}
核心参数解析
参数 | 作用 |
---|---|
corePoolSize | 核心线程数,即最小线程数,线程池初始化时默认不创建线程,只有任务到来时才创建 |
maximumPoolSize | 线程池最大线程数,超过 corePoolSize 后,任务队列满时才会创建新线程 |
keepAliveTime | 线程空闲存活时间,超过 corePoolSize 的额外线程空闲超过该时间后会被销毁 |
unit | keepAliveTime 的时间单位,如 TimeUnit.SECONDS |
workQueue | 存放等待执行的任务队列,如 LinkedBlockingQueue |
threadFactory | 线程创建工厂,默认为 Executors.defaultThreadFactory() |
handler | 线程池饱和后的 拒绝策略,如 AbortPolicy |
3. 线程池的工作流程
线程池的执行逻辑如下:
- 核心线程池是否已满:未满,则创建新线程执行任务。
- 任务队列是否已满:未满,则任务进入队列等待。
- 最大线程池是否已满:未满,则创建新的线程执行任务。
- 线程池已满,任务队列也已满:触发 拒绝策略 处理。
- 空闲线程超过
keepAliveTime
:非核心线程会被回收。
4. Java 内置的线程池(Executors 工具类)
Java 提供了 Executors
工具类,封装了几种常见的线程池:
1️⃣ 固定大小线程池(FixedThreadPool)
ExecutorService fixedPool = Executors.newFixedThreadPool(5);
特点:
- 线程数固定,任务队列无限长,适用于 长期执行的固定任务。
- 线程空闲时不会被销毁。
2️⃣ 缓存线程池(CachedThreadPool)
ExecutorService cachedPool = Executors.newCachedThreadPool();
特点:
- 线程数量不固定,空闲 60s 后销毁。
- 适用于 高并发、短时间任务。
3️⃣ 单线程池(SingleThreadExecutor)
ExecutorService singlePool = Executors.newSingleThreadExecutor();
特点:
- 只有一个线程,任务按顺序执行。
- 适用于 任务串行执行的场景。
4️⃣ 定时任务线程池(ScheduledThreadPool)
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(3);
特点:
- 支持 延迟执行 和 周期执行。
- 适用于 定时任务。
示例:
scheduledPool.schedule(() -> System.out.println("延迟任务"), 3, TimeUnit.SECONDS);
5. 线程池的拒绝策略
当线程池达到 maximumPoolSize
,且任务队列已满时,会触发 拒绝策略:
拒绝策略 | 说明 |
---|---|
AbortPolicy | 默认策略,直接抛出 RejectedExecutionException |
CallerRunsPolicy | 调用线程执行任务,防止丢失 |
DiscardPolicy | 直接丢弃新任务,不抛异常 |
DiscardOldestPolicy | 丢弃最早的任务,尝试提交新任务 |
示例:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 30, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
6. 线程池实战代码
6.1 自定义线程池
import java.util.concurrent.*;
public class ThreadPoolExample {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 30, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
for (int i = 0; i < 20; i++) {
final int taskNum = i;
executor.execute(() -> {
System.out.println("执行任务 " + taskNum + " 线程: " + Thread.currentThread().getName());
});
}
executor.shutdown();
}
}
7. 线程池的常见问题及优化
问题 1:任务堆积导致 OOM
- 原因:任务过多,队列无限增长。
- 解决方案:使用 有界队列,限制任务数量。
问题 2:线程泄漏
- 原因:未正确关闭线程池。
- 解决方案:调用
shutdown()
或shutdownNow()
。
问题 3:CPU 资源浪费
- 原因:
maximumPoolSize
设太大,频繁创建/销毁线程。 - 解决方案:设置合理的 核心线程数。
8. 结论
✅ 线程池是 Java 并发编程的核心组件,提供了 线程复用、任务管理 能力。
✅ ThreadPoolExecutor
提供了 参数化控制,可以灵活管理线程生命周期。
✅ Executors
提供了 固定、缓存、单线程、定时 线程池,适用于不同场景。
✅ 拒绝策略 保障线程池稳定性,避免任务堆积。
掌握线程池的使用技巧,可以让你的 Java 并发编程更加高效、稳定!🚀
开源一个纯AI生成的健身记录App,如需源码,可关注公众号:小健学Java,回复“健身”即可获得!
如需Java面试题资料,可关注公众号:小健学Java,回复“面试”即可获得!