目录
[1. corePoolSize(核心线程数)](#1. corePoolSize(核心线程数))
[2. maximumPoolSize(最大线程数)](#2. maximumPoolSize(最大线程数))
[3. keepAliveTime + unit(空闲线程存活时间)](#3. keepAliveTime + unit(空闲线程存活时间))
[4. workQueue(任务阻塞队列)](#4. workQueue(任务阻塞队列))
[5. threadFactory(线程工厂)](#5. threadFactory(线程工厂))
[6. RejectedExecutionHandler(拒绝策略)](#6. RejectedExecutionHandler(拒绝策略))
[四、使用 Executors 创建常见线程池](#四、使用 Executors 创建常见线程池)
[1. FixedThreadPool(固定大小线程池)](#1. FixedThreadPool(固定大小线程池))
[2. SingleThreadExecutor(单线程线程池)](#2. SingleThreadExecutor(单线程线程池))
[3. CachedThreadPool(缓存线程池)](#3. CachedThreadPool(缓存线程池))
[4. ScheduledThreadPool(定时 / 周期性线程池)](#4. ScheduledThreadPool(定时 / 周期性线程池))
[Executors 创建线程池的弊端(重要)](#Executors 创建线程池的弊端(重要))
在 Java 并发编程中,线程池 是核心组件之一,它通过复用线程、统一管理线程生命周期,解决了频繁创建 / 销毁线程带来的性能开销、资源耗尽、线程不可控等问题。本文将系统总结线程池的核心参数、工作流程,以及Executors工具类创建常用线程池的方式,帮你快速掌握线程池的核心知识。
一、线程池的核心价值
为什么要使用线程池?直接new Thread()创建线程有哪些弊端?
- 降低资源消耗:复用已创建的线程,避免频繁创建 / 销毁线程的开销;
- 提高响应速度:任务到达时,无需等待线程创建即可立即执行;
- 统一管理线程:控制线程数量、调度任务,避免无限制创建线程导致 OOM;
- 增强可扩展性:支持定时、周期性、批量任务执行。
Java 中线程池的顶层接口是Executor,核心实现类是ThreadPoolExecutor,我们日常使用的线程池,本质都是基于这个类封装而来。
二、线程池核心参数详解
ThreadPoolExecutor的全参构造函数是理解线程池的关键,7 个核心参数决定了线程池的行为:
java
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 非核心线程空闲存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
)
1. corePoolSize(核心线程数)
- 线程池中长期存活的核心线程数量,即使空闲也不会被销毁(默认);
- 是线程池的基础线程容量,建议根据 CPU 核心数设置:
- CPU 密集型任务:
corePoolSize = CPU核心数 + 1- IO 密集型任务:
corePoolSize = 2 * CPU核心数
2. maximumPoolSize(最大线程数)
- 线程池能容纳的最大线程总数 = 核心线程 + 非核心线程;
- 当任务队列满了之后,线程池才会创建非核心线程,直到达到该值;
- 该值不能小于
corePoolSize。
3. keepAliveTime + unit(空闲线程存活时间)
- 仅对非核心线程生效:当非核心线程空闲时间超过该值,会被自动销毁,释放资源;
- 可以通过
allowCoreThreadTimeOut(true)开启核心线程的超时销毁功能。
4. workQueue(任务阻塞队列)
- 存储等待执行任务的队列,所有核心线程忙碌时,新任务会放入该队列;
- 常用队列类型:
ArrayBlockingQueue:有界队列,必须指定容量,防止资源耗尽;LinkedBlockingQueue:无界 / 有界队列,不指定容量时可无限添加任务,易引发 OOM;SynchronousQueue:不存储元素的队列,插入任务必须立即有线程接收,否则创建新线程。
5. threadFactory(线程工厂)
- 用于创建新线程的工具,默认使用
Executors.defaultThreadFactory();- 自定义线程工厂可以设置线程名称、优先级、守护线程属性,方便问题排查。
6. RejectedExecutionHandler(拒绝策略)
- 当线程数达到 maximumPoolSize 且任务队列已满时,线程池触发拒绝策略;
- JDK 提供 4 种默认拒绝策略:
AbortPolicy(默认):直接抛出RejectedExecutionException,阻止任务提交;CallerRunsPolicy:让提交任务的主线程自己执行该任务;DiscardPolicy:直接丢弃当前任务,不抛出异常;DiscardOldestPolicy:丢弃队列中最老的任务,尝试提交新任务。
三、线程池的工作流程
线程池的执行逻辑是固定的标准化流程,理解流程就能掌握线程池的调度规则:
- 提交任务 :调用
execute()或submit()向线程池提交任务;- 判断核心线程 :如果当前运行线程数 <
corePoolSize,立即创建核心线程执行任务;- 判断任务队列 :如果核心线程已满,将任务加入阻塞队列等待执行;
- 判断最大线程 :如果队列已满,且当前运行线程数 <
maximumPoolSize,创建非核心线程执行任务;- 执行拒绝策略 :如果线程数达到
maximumPoolSize且队列已满,按照指定拒绝策略处理任务。
流程图解:提交任务 → 核心线程未满?→ 创建核心线程执行→ 核心线程已满 → 任务队列未满?→ 加入队列等待→ 队列已满 → 最大线程未满?→ 创建非核心线程执行→ 最大线程已满 → 执行拒绝策略
补充:线程执行完任务后,会循环从任务队列中获取新任务执行,实现线程复用。
四、使用 Executors 创建常见线程池
Java 提供Executors工具类,封装了 4 种常用的线程池,底层都是基于ThreadPoolExecutor实现,适合快速开发 (生产环境建议手动创建ThreadPoolExecutor,规避资源风险)。
1. FixedThreadPool(固定大小线程池)
java
// 创建固定5个线程的线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
- 核心参数 :
corePoolSize = maximumPoolSize = 指定值,无空闲线程(无非核心线程),队列使用LinkedBlockingQueue(无界);- 特点:线程数固定,所有任务都在核心线程执行,队列无界;
- 适用场景 :控制线程最大并发数,适用于稳定的并发任务场景。
2. SingleThreadExecutor(单线程线程池)
java
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
- 核心参数 :
corePoolSize = maximumPoolSize = 1,仅一个核心线程,队列无界;- 特点 :所有任务串行执行,保证任务执行顺序;
- 适用场景 :需要保证任务顺序执行的场景(如日志写入、单任务串行处理)。
3. CachedThreadPool(缓存线程池)
java
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
- 核心参数 :
corePoolSize = 0,maximumPoolSize = Integer.MAX_VALUE,空闲线程存活 60 秒,队列SynchronousQueue;- 特点:无核心线程,线程数无上限,空闲线程自动销毁;
- 适用场景 :大量短生命周期、高并发的轻量任务,不适合长时间执行的任务。
4. ScheduledThreadPool(定时 / 周期性线程池)
java
// 创建核心线程数为3的定时线程池
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
核心参数 :基于
ScheduledThreadPoolExecutor实现,支持延迟执行、周期性执行;常用方法 :
java// 延迟3秒执行任务 scheduledThreadPool.schedule(() -> {}, 3, TimeUnit.SECONDS); // 初始延迟1秒,每隔2秒周期性执行 scheduledThreadPool.scheduleAtFixedRate(() -> {}, 1, 2, TimeUnit.SECONDS);适用场景 :定时任务、周期性任务(如定时报表、定时数据同步)。
Executors 创建线程池的弊端(重要)
Executors封装的线程池存在资源风险,生产环境不推荐使用:
FixedThreadPool/SingleThreadExecutor:使用无界队列,可能导致大量任务堆积,引发 OOM;CachedThreadPool/ScheduledThreadPool:最大线程数无上限,可能创建大量线程,导致系统崩溃。
最佳实践 :生产环境直接使用ThreadPoolExecutor手动指定参数,自定义队列容量和拒绝策略。
五、总结
- 线程池的核心是
ThreadPoolExecutor,7 个参数决定线程池的调度、容量、容错能力;- 工作流程遵循:核心线程 → 任务队列 → 非核心线程 → 拒绝策略;
Executors提供 4 种常用线程池,适合快速开发,生产环境建议手动创建线程池;- 使用线程池的核心目标:复用线程、控制并发、提升性能、保证系统稳定。
掌握线程池的核心原理和使用规范,是编写高效、稳定 Java 并发程序的基础。
总结
- 核心参数:7 个参数(核心线程数、最大线程数、存活时间、队列、线程工厂、拒绝策略)是线程池的灵魂;
- 工作流程:核心线程→任务队列→非核心线程→拒绝策略,固定调度逻辑;
- 常用线程池 :
Executors提供固定、单线程、缓存、定时四种线程池,生产环境优先手动创建ThreadPoolExecutor。