线程池详解
一、线程池核心概念
作用:通过池化技术复用线程,减少创建/销毁开销,提高资源利用率,避免因线程过多导致系统崩溃。
优势:
- 降低资源消耗:复用已创建的线程,减少频繁创建销毁的开销。
- 提高响应速度:任务到达时可直接执行,无需等待线程创建。
- 增强管理性:统一管理任务队列、线程数及异常处理。
二、核心参数(ThreadPoolExecutor)
线程池通过 ThreadPoolExecutor
类实现,构造函数包含以下关键参数:
-
corePoolSize(核心线程数)
- 默认常驻的线程数量,即使空闲也不会销毁(除非设置
allowCoreThreadTimeOut
)。
- 默认常驻的线程数量,即使空闲也不会销毁(除非设置
-
maximumPoolSize(最大线程数)
- 线程池允许创建的最大线程数,当队列满且核心线程繁忙时启用。
-
keepAliveTime(线程存活时间)
- 非核心线程的空闲存活时间,超时后销毁。
-
unit(时间单位)
keepAliveTime
的时间单位(如秒、毫秒)。
-
workQueue(任务队列)
- 存储待执行任务的阻塞队列,常用实现类:
LinkedBlockingQueue
:无界队列(可能导致OOM)。ArrayBlockingQueue
:有界队列。SynchronousQueue
:直接提交队列(无缓冲)。
- 存储待执行任务的阻塞队列,常用实现类:
-
threadFactory(线程工厂)
- 用于创建线程,可自定义线程名称、优先级等。
-
handler(拒绝策略)
- 当线程池和队列均满时的处理策略,内置策略:
AbortPolicy
(默认):抛出RejectedExecutionException
。CallerRunsPolicy
:由提交任务的线程执行任务。DiscardPolicy
:静默丢弃新任务。DiscardOldestPolicy
:丢弃队列中最旧的任务,重新提交新任务。
- 当线程池和队列均满时的处理策略,内置策略:
三、线程池工作流程
-
任务提交
- 调用
execute(Runnable task)
或submit(Callable task)
提交任务。
- 调用
-
执行流程
- 若当前线程数 <
corePoolSize
,立即创建新线程执行任务。 - 若线程数 ≥
corePoolSize
,任务进入workQueue
等待。 - 若队列已满且线程数 <
maximumPoolSize
,创建非核心线程执行任务。 - 若队列和线程数均满,触发拒绝策略。
- 若当前线程数 <
四、常见线程池类型(通过Executors创建)
-
FixedThreadPool
- 固定线程数,使用无界队列
LinkedBlockingQueue
。 - 风险:任务堆积可能导致OOM。
- 固定线程数,使用无界队列
-
CachedThreadPool
- 线程数动态调整(0到Integer.MAX_VALUE),适合短时异步任务。
- 风险:高并发下可能创建大量线程,导致资源耗尽。
-
SingleThreadExecutor
- 单线程执行任务,确保任务顺序执行(如日志处理)。
-
ScheduledThreadPool
- 支持定时或周期性任务执行。
避免使用Executors快捷方法
推荐手动创建
ThreadPoolExecutor
,明确参数配置,防止隐含风险(如无界队列)
五、示例代码
// 手动创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, // corePoolSize5, // maximumPoolSize60, TimeUnit.SECONDS, // keepAliveTimenew ArrayBlockingQueue<>(100), // workQueueExecutors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy()
);// 提交任务
executor.execute(() -> System.out.println("Task executed by " + Thread.currentThread().getName()));// 关闭线程池
executor.shutdown();
六、配置建议
1. CPU 密集型任务配置
特点:计算逻辑复杂,CPU 占用率高(如加密解密、数学运算、数据处理等)。
配置示例
import java.util.concurrent.*;public class CpuIntensiveExample {public static void main(String[] args) {int cpuCores = Runtime.getRuntime().availableProcessors();// 线程池参数配置int corePoolSize = cpuCores + 1; // 核心线程数 = CPU 核数 + 1int maxPoolSize = corePoolSize; // 最大线程数 = 核心线程数(不扩容)int queueCapacity = 100; // 有界队列容量ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maxPoolSize,0L, // 空闲线程立即回收(核心线程常驻)TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(queueCapacity), // 有界队列防止 OOMExecutors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略:提交线程执行任务);// 提交任务示例for (int i = 0; i < 1000; i++) {executor.submit(() -> {heavyCalculation(); // CPU 密集型计算});}executor.shutdown();}private static void heavyCalculation() {// 模拟复杂计算(如矩阵运算、加密等)}
}
参数说明
参数 | 值/策略 | 原因 |
---|---|---|
corePoolSize | CPU 核数 + 1 | 充分利用 CPU 资源,减少上下文切换。 |
maxPoolSize | 与 corePoolSize 相同 | CPU 密集型任务无需扩容,避免额外线程竞争 CPU。 |
workQueue | ArrayBlockingQueue | 有界队列防止任务堆积导致 OOM。 |
keepAliveTime | 0 | 核心线程常驻,无需回收。 |
RejectedExecutionHandler | CallerRunsPolicy | 任务由提交线程执行,避免任务丢失,同时减缓提交速率。 |
2. IO 密集型任务配置
特点:任务频繁等待 IO(如数据库查询、网络请求、文件读写等)。
配置示例
import java.util.concurrent.*;public class IoIntensiveExample {public static void main(String[] args) {int cpuCores = Runtime.getRuntime().availableProcessors();// 线程池参数配置int corePoolSize = cpuCores * 2; // 核心线程数 = CPU 核数 × 2int maxPoolSize = cpuCores * 4; // 最大线程数 = CPU 核数 × 4(应对突发流量)int queueCapacity = 200; // 队列容量ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maxPoolSize,30L, // 非核心线程空闲 30 秒后回收TimeUnit.SECONDS,new LinkedBlockingQueue<>(queueCapacity), // 无界队列需谨慎使用Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy() // 拒绝策略:抛异常(需业务处理));// 提交任务示例for (int i = 0; i < 1000; i++) {executor.submit(() -> {queryDatabase(); // 模拟 IO 操作(如数据库访问)});}executor.shutdown();}private static void queryDatabase() {// 模拟 IO 操作(如 JDBC 查询)}
}
参数说明
参数 | 值/策略 | 原因 |
---|---|---|
corePoolSize | CPU 核数 × 2 | 更多线程应对 IO 等待,提高吞吐量。 |
maxPoolSize | CPU 核数 × 4 | 突发流量时扩容线程,避免任务堆积。 |
workQueue | LinkedBlockingQueue | 缓冲突发任务,需设置合理容量(避免无界队列导致 OOM)。 |
keepAliveTime | 30 秒 | 非核心线程空闲时回收,节省资源。 |
RejectedExecutionHandler | AbortPolicy | 任务满时抛异常,需业务捕获并处理(如降级、重试)。 |
3. 混合型任务配置
特点:既有 CPU 计算,也有 IO 等待(如 Web 服务中的请求处理)。
动态计算公式
// 根据 IO 等待时间占比动态计算最大线程数
double ioWaitRatio = 0.7; // 假设 70% 时间在等待 IO
int maxThreads = (int) (cpuCores / (1 - ioWaitRatio)); // 例如 4核 → 13线程ThreadPoolExecutor executor = new ThreadPoolExecutor(cpuCores * 2, // 核心线程数maxThreads, // 最大线程数60L, TimeUnit.SECONDS,new SynchronousQueue<>() // 直接传递任务,无缓冲
);
4. 注意事项
-
队列选择:
- CPU 密集型:优先使用
ArrayBlockingQueue
(有界队列)。 - IO 密集型:可使用
LinkedBlockingQueue
,但需指定容量。 - 高吞吐场景:
SynchronousQueue
(无缓冲,需快速响应)。
- CPU 密集型:优先使用
-
拒绝策略:
AbortPolicy
:直接抛异常(需业务处理)。CallerRunsPolicy
:提交线程执行任务(减缓提交速率)。DiscardPolicy
:静默丢弃任务(慎用)。
-
监控与调优:
- 监控指标:
活跃线程数
、队列堆积
、拒绝任务数
。 - 动态调整:通过
setCorePoolSize()
和setMaximumPoolSize()
动态修改参数。
- 监控指标: