题目
Java中如何创建一个固定大小的线程池?
信息
- 类型:问答
- 难度:⭐
考点
线程池创建,ExecutorService接口,核心线程数配置
快速回答
在Java中创建固定大小线程池的两种方式:
- 使用
Executors.newFixedThreadPool(int nThreads)工厂方法 - 直接配置
ThreadPoolExecutor参数(更灵活)
核心参数说明:
- corePoolSize:线程池保留的核心线程数
- maximumPoolSize:最大线程数(固定线程池中等于corePoolSize)
- keepAliveTime:非核心线程空闲存活时间(固定线程池中为0)
1. 线程池的作用
线程池主要解决频繁创建/销毁线程的开销问题,通过复用线程提高系统性能,同时提供任务队列和线程管理功能。
2. 创建固定线程池的两种方式
方式一:使用Executors工厂方法(推荐简单场景)
// 创建固定大小为4的线程池
ExecutorService executor = Executors.newFixedThreadPool(4);
// 提交任务
executor.execute(() -> {
System.out.println("任务执行线程: " + Thread.currentThread().getName());
});
// 关闭线程池(重要!)
executor.shutdown();特点:
- 核心线程数 = 最大线程数 = 指定参数
- 使用无界队列(LinkedBlockingQueue),可能导致OOM
方式二:手动配置ThreadPoolExecutor(更可控)
int corePoolSize = 4;
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize, // 核心线程数
corePoolSize, // 最大线程数(与核心数相同)
0L, // 空闲线程存活时间
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>() // 任务队列
);优势:可自定义队列类型(如指定队列容量避免OOM)
3. 核心参数详解
| 参数 | 说明 | 固定线程池取值 |
|---|---|---|
| corePoolSize | 核心线程数,即使空闲也不会销毁 | 用户指定值 |
| maximumPoolSize | 线程池最大线程数 | 等于corePoolSize |
| keepAliveTime | 非核心线程空闲存活时间 | 0(因无非核心线程) |
| workQueue | 任务等待队列 | 无界LinkedBlockingQueue |
4. 最佳实践与注意事项
- 必须关闭线程池:调用
shutdown()或shutdownNow()避免资源泄漏 - 队列选择:生产环境建议使用有界队列(如
new ArrayBlockingQueue<>(100)) - 异常处理:通过
ThreadFactory设置UncaughtExceptionHandler - 资源限制:根据CPU核心数设置线程数(通常N+1,N为CPU核心数)
5. 常见错误
- 忘记关闭线程池:导致JVM无法退出
- 使用无界队列:任务暴增时引发OOM
- 线程数设置过大:过多线程竞争CPU反而降低性能
- 捕获任务异常:Runnable任务需自行处理异常,否则异常会丢失
6. 扩展知识
- 其他线程池类型:
-newCachedThreadPool():弹性线程池
-newSingleThreadExecutor():单线程池 - 任务提交方式:
-execute():提交Runnable无返回值
-submit():可提交Callable获取Future结果 - 拒绝策略:当队列满且线程达上限时触发(如AbortPolicy抛出异常)