线程池参数有什么
概述
- 定义:
- 线程池(
ThreadPoolExecutor
)是 Java 并发框架中用于管理线程的工具,通过复用线程执行任务,避免频繁创建/销毁线程的开销。 ThreadPoolExecutor
的行为由多个参数控制,这些参数决定线程池的大小、任务处理策略、线程生命周期等。- 核心点:
ThreadPoolExecutor
有 7 个核心参数,通过构造函数配置,影响线程池的性能、并发能力和资源使用。- 正确配置参数需根据任务特性(CPU 密集型、I/O 密集型)、并发量和硬件资源进行调优。
1. 线程池参数详解
ThreadPoolExecutor
的构造函数如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
以下是 7 个参数的详细说明:
(1) corePoolSize(核心线程数)
- 定义:
- 线程池中常驻的核心线程数量,即使这些线程空闲也不会销毁(除非设置
allowCoreThreadTimeOut
)。 - 作用:
- 决定线程池的基本并发能力。
- 新任务到来时,若当前线程数 <
corePoolSize
,创建新线程执行任务。 - 典型值:
- CPU 密集型任务:
CPU 核心数
或CPU 核心数 + 1
。 - I/O 密集型任务:
2 * CPU 核心数
或更高,考虑阻塞时间。 - 示例:
java int corePoolSize = Runtime.getRuntime().availableProcessors(); // CPU 核心数
(2) maximumPoolSize(最大线程数)
- 定义:
- 线程池允许创建的最大线程数量,包括核心线程和非核心线程。
- 作用:
- 当任务队列满且线程数 <
maximumPoolSize
时,创建非核心线程处理任务。 - 非核心线程在空闲时会受
keepAliveTime
控制销毁。 - 典型值:
- 根据系统资源(CPU、内存)和任务并发量设置。
- 过大可能导致资源耗尽,过小可能限制并发。
- 示例:
java int maximumPoolSize = corePoolSize * 2; // 两倍核心线程
(3) keepAliveTime(非核心线程空闲存活时间)
- 定义:
- 非核心线程(超过
corePoolSize
的线程)空闲时允许存活的时间,超时后销毁。 - 若设置
allowCoreThreadTimeOut(true)
,核心线程也受此参数控制。 - 作用:
- 控制线程池的动态伸缩,释放空闲线程以节省资源。
- 典型值:
- 几十秒到几分钟(如 60 秒),根据任务到达频率调整。
- 示例:
java long keepAliveTime = 60; // 60 秒
(4) unit(时间单位)
- 定义:
keepAliveTime
的时间单位,来自java.util.concurrent.TimeUnit
。- 可选值:
NANOSECONDS
,MICROSECONDS
,MILLISECONDS
,SECONDS
,MINUTES
,HOURS
,DAYS
。- 作用:
- 指定
keepAliveTime
的单位,通常用SECONDS
或MILLISECONDS
。 - 示例:
java TimeUnit unit = TimeUnit.SECONDS;
(5) workQueue(任务队列)
- 定义:
- 用于存储待执行任务的阻塞队列,当线程数达到
corePoolSize
时,新任务进入队列。 - 常见实现:
- LinkedBlockingQueue:无界队列(默认容量
Integer.MAX_VALUE
),可能导致内存溢出。 - ArrayBlockingQueue:有界队列,固定容量,适合控制任务堆积。
- SynchronousQueue:无缓冲队列,直接移交任务,需线程立即处理。
- PriorityBlockingQueue:优先级队列,按任务优先级排序。
- 作用:
- 缓冲任务,平滑任务高峰,影响任务堆积和拒绝策略。
- 典型值:
- 有界队列(如
ArrayBlockingQueue(100)
)避免无限堆积。 - 无界队列(如
LinkedBlockingQueue
)适合任务量可控场景。 - 示例:
java BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100);
(6) threadFactory(线程工厂)
- 定义:
- 用于创建线程的工厂,控制线程属性(如名称、优先级、守护线程)。
- 作用:
- 自定义线程名称(便于调试)、设置线程组或优先级。
- 默认:
Executors.defaultThreadFactory()
,创建普通非守护线程。 - 示例:
java ThreadFactory threadFactory = new ThreadFactory() { private final AtomicInteger threadNumber = new AtomicInteger(1); @Override public Thread newThread(Runnable r) { Thread t = new Thread(r, "MyPool-Thread-" + threadNumber.getAndIncrement()); t.setDaemon(false); t.setPriority(Thread.NORM_PRIORITY); return t; } };
(7) handler(拒绝策略)
- 定义:
- 当任务队列满且线程数达到
maximumPoolSize
时,处理新任务的策略。 - 内置策略:
- AbortPolicy(默认):抛出
RejectedExecutionException
,拒绝任务。 - CallerRunsPolicy:调用者线程执行任务,减缓提交速度。
- DiscardPolicy:静默丢弃任务,不抛异常。
- DiscardOldestPolicy:丢弃队列头部(最旧)任务,尝试加入新任务。
- 作用:
- 控制任务溢出行为,影响系统稳定性和任务丢失。
- 自定义策略:
- 实现
RejectedExecutionHandler
接口,例如记录日志或重试。 - 示例:
java RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
2. 线程池参数的工作流程
ThreadPoolExecutor
根据参数处理任务的流程:
1. 任务提交:
- 若线程数 < corePoolSize
,创建核心线程执行任务。
- 若线程数 ≥ corePoolSize
,任务进入 workQueue
。
2. 队列满:
- 若队列满且线程数 < maximumPoolSize
,创建非核心线程。
- 若线程数 = maximumPoolSize
,执行 handler
的拒绝策略。
3. 空闲线程:
- 非核心线程空闲超过 keepAliveTime
,销毁。
- 核心线程默认存活,除非设置 allowCoreThreadTimeOut(true)
。
流程图:
提交任务
|
线程数 < corePoolSize? -> 创建核心线程 -> 执行任务
|
队列未满? -> 任务入队 -> 等待线程执行
|
线程数 < maximumPoolSize? -> 创建非核心线程 -> 执行任务
|
执行拒绝策略 (handler)
3. 参数配置示例
import java.util.concurrent.*;
public class ThreadPoolExample {
public static void main(String[] args) {
// 参数配置
int corePoolSize = 2; // 2 个核心线程
int maximumPoolSize = 4; // 最多 4 个线程
long keepAliveTime = 60; // 非核心线程空闲 60 秒
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10); // 队列容量 10
ThreadFactory threadFactory = Executors.defaultThreadFactory();
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
// 创建线程池
ThreadPoolExecutor pool = new ThreadPoolExecutor(
corePoolSize, maximumPoolSize, keepAliveTime, unit,
workQueue, threadFactory, handler);
// 提交任务
for (int i = 0; i < 20; i++) {
final int taskId = i;
pool.submit(() -> {
System.out.println("Task " + taskId + " running in " + Thread.currentThread().getName());
try { Thread.sleep(1000); } catch (InterruptedException e) {}
});
}
// 关闭线程池
pool.shutdown();
}
}
说明:
- 核心线程 2 个,队列容量 10,最大线程 4 个。
- 提交 20 个任务:
- 2 个任务立即由核心线程执行。
- 10 个任务进入队列。
- 2 个任务触发创建非核心线程(总线程数达 4)。
- 剩余 6 个任务触发 CallerRunsPolicy
,由提交线程执行。
4. 参数调优建议
- corePoolSize:
- CPU 密集型:
CPU 核心数
或+1
,避免过多线程切换。 - I/O 密集型:
2 * CPU 核心数
或更高,适应阻塞任务。 - 示例:8 核 CPU,CPU 密集型设 8,I/O 密集型设 16。
- maximumPoolSize:
- 设为核心线程的 2-4 倍,视内存和任务量而定。
- 避免过大导致 OOM(Out of Memory)。
- keepAliveTime:
- 设为几十秒(如 60 秒),平衡线程复用和资源释放。
- 高峰任务频繁时可延长(如 300 秒)。
- workQueue:
- 有界队列(
ArrayBlockingQueue
)控制堆积,容量 50-1000 视任务量。 - 无界队列(
LinkedBlockingQueue
)谨慎使用,防止内存溢出。 SynchronousQueue
适合快速移交任务(如CachedThreadPool
)。- threadFactory:
- 自定义线程名称,便于调试(如
MyPool-Thread-1
)。 - 避免设置守护线程,确保任务完成。
- handler:
CallerRunsPolicy
适合减缓提交速度,防止系统过载。AbortPolicy
适合严格拒绝,配合异常处理。- 自定义策略可记录日志或重试。
5. 注意事项
- 队列容量:
- 无界队列可能导致任务堆积,内存溢出。
- 有界队列需配合
maximumPoolSize
和handler
防止拒绝过多。 - 线程泄漏:
- 任务执行时间过长或未正确关闭池,可能导致线程不释放。
- 使用
shutdown()
或shutdownNow()
确保资源回收。 - 拒绝策略风险:
DiscardPolicy
和DiscardOldestPolicy
可能丢失任务,需评估业务影响。- 核心线程销毁:
- 默认核心线程不销毁,若需销毁,设置:
java pool.allowCoreThreadTimeOut(true);
- 性能监控:
- 使用
ThreadPoolExecutor
的方法(如getActiveCount()
、getQueue().size()
)监控线程和队列状态。 - 示例:
java System.out.println("Active threads: " + pool.getActiveCount()); System.out.println("Queue size: " + pool.getQueue().size());
- Executors 工厂:
Executors
提供的线程池(如newFixedThreadPool
、newCachedThreadPool
)是ThreadPoolExecutor
的简化配置,可能不适合复杂场景。- 示例:
newFixedThreadPool(n)
:corePoolSize = maximumPoolSize = n
,无界队列。newCachedThreadPool()
:corePoolSize = 0
,maximumPoolSize = Integer.MAX_VALUE
,SynchronousQueue
。
6. 面试角度
- 问“线程池有哪些参数”:
- 提 7 个参数:
corePoolSize
、maximumPoolSize
、keepAliveTime
、unit
、workQueue
、threadFactory
、handler
,说明作用。 - 问“corePoolSize 和 maximumPoolSize 区别”:
- 提核心线程常驻,空闲不销毁;最大线程数包括非核心线程,空闲超时销毁。
- 问“workQueue 种类和选择”:
- 提
LinkedBlockingQueue
(无界)、ArrayBlockingQueue
(有界)、SynchronousQueue
(无缓冲),根据任务量和堆积选择。 - 问“拒绝策略如何选”:
- 提
AbortPolicy
(抛异常)、CallerRunsPolicy
(减速)、DiscardPolicy
(丢弃)、DiscardOldestPolicy
(丢最旧),根据业务容忍度选。 - 问“如何调优线程池”:
- 提 CPU/I/O 密集型设置
corePoolSize
,有界队列控制堆积,CallerRunsPolicy
防过载,监控线程/队列状态。 - 问“无界队列的风险”:
- 提任务堆积导致内存溢出,建议用有界队列或自定义拒绝策略。
7. 总结
- 线程池参数:
- corePoolSize:核心线程数,常驻线程。
- maximumPoolSize:最大线程数,控制总并发。
- keepAliveTime:非核心线程空闲存活时间。
- unit:时间单位(如秒)。
- workQueue:任务队列(有界/无界/同步)。
- threadFactory:线程工厂,定制线程属性。
- handler:拒绝策略,处理任务溢出。
- 工作机制:
- 核心线程 → 队列 → 非核心线程 → 拒绝策略。
- 调优建议:
- 根据任务类型(CPU/I/O)设
corePoolSize
和maximumPoolSize
。 - 用有界队列防堆积,
CallerRunsPolicy
防过载。 - 自定义
threadFactory
便于调试,监控线程/队列状态。 - 面试建议:
- 提 7 参数、作用、工作流程、调优策略(CPU vs I/O)、队列/拒绝风险,举代码(
ThreadPoolExecutor
配置),清晰展示理解。