线程池参数如何设置才靠谱
线程池是 Java 并发编程中最重要的工具之一。合理配置线程池参数,能显著提升系统性能和稳定性。
ThreadPoolExecutor 核心参数
public ThreadPoolExecutor( int corePoolSize, // 核心线程数 int maximumPoolSize, // 最大线程数 long keepAliveTime, // 空闲线程存活时间 TimeUnit unit, // 时间单位 BlockingQueue<Runnable> workQueue, // 任务队列 ThreadFactory threadFactory, // 线程工厂 RejectedExecutionHandler handler // 拒绝策略 )
|
参数详解
corePoolSize(核心线程数)
线程池维护的最小线程数,即使空闲也保留。
maximumPoolSize(最大线程数)
线程池允许的最大线程数。
workQueue(任务队列)
| 队列类型 |
特点 |
| ArrayBlockingQueue |
有界数组队列,需指定容量 |
| LinkedBlockingQueue |
无界链表队列(默认Integer.MAX_VALUE) |
| SynchronousQueue |
不存储元素,直接提交给线程 |
| PriorityBlockingQueue |
优先级队列 |
注意:Executors.newFixedThreadPool() 使用无界 LinkedBlockingQueue,可能导致 OOM!
拒绝策略
| 策略 |
行为 |
| AbortPolicy |
抛出RejectedExecutionException(默认) |
| CallerRunsPolicy |
由调用线程执行任务 |
| DiscardPolicy |
静默丢弃任务 |
| DiscardOldestPolicy |
丢弃最老的任务,重试提交 |
线程池工作流程
提交任务 | v 核心线程是否已满? --否--> 创建核心线程执行任务 |是 v 队列是否已满? --否--> 任务入队等待 |是 v 最大线程是否已满? --否--> 创建非核心线程执行任务 |是 v 执行拒绝策略
|
参数设置公式
CPU 密集型任务
任务主要进行计算,很少阻塞。
corePoolSize = CPU核心数 + 1 maximumPoolSize = corePoolSize
|
原因:
- CPU 密集型任务应尽量减少线程切换
- 多一个线程是为了充分利用 CPU 时间片
int cpuCore = Runtime.getRuntime().availableProcessors(); int poolSize = cpuCore + 1;
|
IO 密集型任务
任务涉及网络、磁盘等 IO 操作,线程会大量阻塞。
corePoolSize = CPU核心数 * 2 maximumPoolSize = CPU核心数 * 2 + 1
|
原因:
- IO 阻塞时 CPU 空闲,需要更多线程提高利用率
- 具体数值需根据实际 IO 等待时间调整
通用公式(更精确)
corePoolSize = CPU核心数 / (1 - 阻塞系数)
阻塞系数 = 阻塞时间 / (阻塞时间 + 计算时间)
|
| 任务类型 |
阻塞系数 |
| 纯计算 |
0 |
| 少量 IO |
0.3~0.5 |
| 大量 IO |
0.8~0.9 |
示例:
int coreForCompute = (int) (cpuCore / (1 - 0.1));
int coreForIO = (int) (cpuCore / (1 - 0.8));
|
实际配置示例
异步处理线程池
@Bean("asyncExecutor") public Executor asyncExecutor() { int cpuCore = Runtime.getRuntime().availableProcessors(); ThreadPoolExecutor executor = new ThreadPoolExecutor( cpuCore * 2, cpuCore * 4, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), new ThreadFactoryBuilder().setNameFormat("async-%d").build(), new ThreadPoolExecutor.CallerRunsPolicy() ); executor.allowCoreThreadTimeOut(true); return executor; }
|
定时任务线程池
@Bean("scheduledExecutor") public ScheduledExecutorService scheduledExecutor() { return new ScheduledThreadPoolExecutor( 5, new ThreadFactoryBuilder().setNameFormat("schedule-%d").build(), new ThreadPoolExecutor.AbortPolicy() ); }
|
禁止使用 Executors 创建线程池
问题分析
ExecutorService pool = Executors.newFixedThreadPool(100);
ExecutorService pool = Executors.newCachedThreadPool();
ExecutorService pool = Executors.newSingleThreadExecutor();
|
阿里巴巴编码规范
强制线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
线程池监控
public class ThreadPoolMonitor { public static void printStats(ThreadPoolExecutor pool) { System.out.println("核心线程数: " + pool.getCorePoolSize()); System.out.println("最大线程数: " + pool.getMaximumPoolSize()); System.out.println("当前线程数: " + pool.getPoolSize()); System.out.println("活跃线程数: " + pool.getActiveCount()); System.out.println("完成任务数: " + pool.getCompletedTaskCount()); System.out.println("队列任务数: " + pool.getQueue().size()); System.out.println("队列剩余容量: " + pool.getQueue().remainingCapacity()); } }
|
Spring Boot 监控
@Component public class ThreadPoolMetrics { @Autowired private ThreadPoolExecutor executor; @Scheduled(fixedRate = 60000) public void report() { log.info("线程池状态 - 活跃: {}, 队列: {}, 完成: {}", executor.getActiveCount(), executor.getQueue().size(), executor.getCompletedTaskCount() ); } }
|
优雅关闭线程池
public void shutdownGracefully(ThreadPoolExecutor executor) { executor.shutdown(); try { if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { executor.shutdownNow(); if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { System.err.println("线程池未正常关闭"); } } } catch (InterruptedException e) { executor.shutdownNow(); Thread.currentThread().interrupt(); } }
|
常见问题
1. 任务异常导致线程终止
executor.submit(() -> { throw new RuntimeException("异常"); });
executor.submit(() -> { try { } catch (Exception e) { log.error("任务执行异常", e); } });
|
2. ThreadLocal 内存泄漏
executor.submit(() -> { try { ThreadLocal<String> tl = new ThreadLocal<>(); tl.set("value"); } finally { tl.remove(); } });
|
总结
| 场景 |
corePoolSize |
maximumPoolSize |
队列 |
| 计算密集型 |
CPU+1 |
CPU+1 |
有界队列 |
| IO密集型 |
CPU*2 |
CPU*4 |
有界队列 |
| 混合任务 |
根据公式计算 |
core*2 |
有界队列 |
核心原则:
- 始终使用
ThreadPoolExecutor 手动创建
- 始终使用有界队列
- 根据任务类型选择参数
- 做好监控和优雅关闭
- 注意 ThreadLocal 清理