Java 线程池参数详解
Java 线程池是通过 java.util.concurrent
提供的 Executor 框架实现的。线程池主要由 ThreadPoolExecutor
类支持,它提供了灵活的配置参数,允许开发者根据需求调整线程池的行为和性能。
1. 线程池的构造方法
ThreadPoolExecutor
提供了一个核心构造方法,允许指定线程池的关键参数:
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler
)
2. 线程池参数解析
2.1 核心参数
1. corePoolSize
- 定义:
- 核心线程数,即线程池中始终保持存活的线程数量。
- 即使线程池处于空闲状态,核心线程也不会被回收(默认情况下)。
- 作用:
- 在任务量较少时,线程池会优先创建核心线程来执行任务。
- 配置建议:
- 根据系统负载和任务特性设置。
2. maximumPoolSize
- 定义:
- 线程池中允许的最大线程数(包括核心线程)。
- 当任务队列满时,线程池会继续创建非核心线程,直到达到最大线程数。
- 作用:
- 控制线程池的最大并发能力。
- 配置建议:
- 设置为合适的值以避免线程过多导致系统资源耗尽。
3. keepAliveTime
- 定义:
- 非核心线程的存活时间(当线程处于空闲状态时)。
- 超过此时间未执行任务的非核心线程会被销毁。
- 作用:
- 控制线程池资源的回收效率。
- 配置建议:
- 对于需要快速响应的线程池,可设置较短的存活时间。
4. unit
- 定义:
keepAliveTime
的时间单位。- 取值范围为
TimeUnit
枚举,包括:TimeUnit.MILLISECONDS
(毫秒)TimeUnit.SECONDS
(秒)TimeUnit.MINUTES
(分钟)
- 作用:
- 规范存活时间的粒度。
5. workQueue
- 定义:
- 一个阻塞队列,用于存储等待执行的任务。
- 如果线程池中的线程数已达到
corePoolSize
,新任务会被加入队列等待。
常用队列类型
ArrayBlockingQueue
:- 有界队列,必须指定容量。
- 当队列满时,新任务会触发线程池扩容。
LinkedBlockingQueue
:- 无界队列(理论上容量无限制)。
- 如果使用无界队列,
maximumPoolSize
参数将失效。
SynchronousQueue
:- 不存储任务的队列,每次提交的任务必须直接交给线程处理。
- 如果没有空闲线程,线程池会立即创建新线程。
PriorityBlockingQueue
:- 支持任务排序的队列。
- 提交的任务会根据优先级排序。
6. threadFactory
- 定义:
- 用于创建线程的工厂类。
- 作用:
- 可以自定义线程名称、线程优先级、是否为守护线程等。
- 示例:
ThreadFactory factory = r -> { Thread thread = new Thread(r); thread.setName("CustomThread-" + thread.getId()); return thread; };
7. handler
- 定义:
- 拒绝策略,表示当线程池无法接受新任务时的处理方式。
- 触发场景:
- 当任务队列已满且线程池中的线程数已达到
maximumPoolSize
时。
- 当任务队列已满且线程池中的线程数已达到
- 常见策略(
RejectedExecutionHandler
接口实现):AbortPolicy
(默认):- 抛出
RejectedExecutionException
异常。
- 抛出
CallerRunsPolicy
:- 由提交任务的线程直接执行任务。
DiscardPolicy
:- 丢弃任务,不抛出异常。
DiscardOldestPolicy
:- 丢弃最早的任务(队列头部任务),然后重新尝试提交新任务。
2.2 线程池的工作流程
- 提交任务:
- 任务通过
execute()
或submit()
方法提交到线程池。
- 任务通过
- 任务处理:
- 如果线程数未达到
corePoolSize
,创建新线程处理任务。 - 如果线程数已达到
corePoolSize
,任务进入workQueue
等待。 - 如果队列已满,且线程数小于
maximumPoolSize
,创建新线程处理任务。 - 如果队列已满,且线程数达到
maximumPoolSize
,触发拒绝策略。
- 如果线程数未达到
- 线程回收:
- 超过
keepAliveTime
未使用的非核心线程会被销毁。
- 超过
3. 常用线程池实现
Java 提供了一些线程池的便捷方法:
3.1 Executors
工厂方法
newFixedThreadPool(int nThreads)
:- 固定大小的线程池。
- 核心线程数和最大线程数相等,使用无界队列。
ExecutorService fixedPool = Executors.newFixedThreadPool(5);
newCachedThreadPool()
:- 可缓存线程池。
- 线程池大小无限制,线程空闲超过 60 秒会被回收。
ExecutorService cachedPool = Executors.newCachedThreadPool();
newSingleThreadExecutor()
:- 单线程的线程池。
- 保证任务按提交顺序执行。
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
newScheduledThreadPool(int corePoolSize)
:- 支持定时和周期性任务的线程池。
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(5);
3.2 自定义线程池
通过 ThreadPoolExecutor
构造一个自定义线程池:
ExecutorService customPool = new ThreadPoolExecutor(
2, // 核心线程数
4, // 最大线程数
60, // 非核心线程存活时间
TimeUnit.SECONDS, // 存活时间单位
new ArrayBlockingQueue<>(10), // 阻塞队列
Executors.defaultThreadFactory(), // 默认线程工厂
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);
4. 参数配置的优化建议
4.1 核心线程数(corePoolSize
)
- I/O 密集型任务:
- 核心线程数通常设置为 2 * CPU 核心数。
- 任务需要频繁等待外部资源(如磁盘、网络),线程数可以适当增加。
- CPU 密集型任务:
- 核心线程数设置为 CPU 核心数 + 1。
- 线程数过多会增加上下文切换的开销。
4.2 最大线程数(maximumPoolSize
)
- 线程池的大小应在系统资源允许范围内,避免线程数过多导致资源耗尽。
4.3 队列类型(workQueue
)
- 短任务队列:
- 使用
SynchronousQueue
,不存储任务,适合高吞吐场景。
- 使用
- 有限任务队列:
- 使用
ArrayBlockingQueue
限制队列长度,防止内存溢出。
- 使用
- 优先级队列:
- 使用
PriorityBlockingQueue
,适合需要任务排序的场景。
- 使用
4.4 拒绝策略(handler
)
- 高可靠性:
- 使用
CallerRunsPolicy
,将任务回退到调用线程执行。
- 使用
- 低优先级任务:
- 使用
DiscardPolicy
或DiscardOldestPolicy
丢弃任务。
- 使用
5. 示例代码
import java.util.concurrent.*;
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService threadPool = new ThreadPoolExecutor(
2, // 核心线程数
4, // 最大
线程数
60L, // 空闲线程存活时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(10), // 阻塞队列
Executors.defaultThreadFactory(), // 线程工厂
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
for (int i = 0; i < 20; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + " is executing");
});
}
threadPool.shutdown();
}
}
6. 总结
参数 | 作用 | 优化建议 |
---|---|---|
corePoolSize |
核心线程数,始终存活的线程数 | 根据任务类型和系统资源合理设置 |
maximumPoolSize |
最大线程数,限制线程池最大并发量 | 避免设置过高,防止资源耗尽 |
keepAliveTime |
非核心线程的存活时间 | 根据响应需求调整 |
workQueue |
等待任务队列,存储未处理的任务 | 使用合适的队列类型 |
handler |
拒绝策略,决定任务无法处理时的行为 | 根据任务重要性选择合适的策略 |
通过合理配置线程池参数,可以显著提升多线程程序的性能和资源利用率。