线程池七大参数与线程数设置
更新时间:2026-09-20。线程池用「复用线程 + 排队 + 拒绝」三件事,避免每个任务新建/销毁线程的开销。直接用
Executors工厂是新手最大的坑,生产环境应当用 ThreadPoolExecutor 显式传参。线程与锁基础见 synchronized,排查见 jstack。
一、七大参数
java
ThreadPoolExecutor pool = new ThreadPoolExecutor(
4, // 1 corePoolSize 核心线程(即使空闲也保留)
8, // 2 maximumPoolSize 最大线程
60, TimeUnit.SECONDS, // 3/4 keepAliveTime 非核心线程空闲存活时间
new ArrayBlockingQueue<>(200), // 5 workQueue 任务队列
new ThreadFactoryBuilder().setNameFormat("biz-%d").build(), // 6 线程工厂(命名!)
new ThreadPoolExecutor.CallerRunsPolicy() // 7 拒绝策略
);| 参数 | 含义 | 调大的影响 |
|---|---|---|
| corePoolSize | 常驻线程数 | 平时并发能力↑、空闲线程占内存 |
| maximumPoolSize | 极限线程数 | 高峰承载↑、线程过多反而调度抖 |
| keepAliveTime | 多余线程空闲回收时间 | 回收快慢 |
| workQueue | 核心线程忙时的排队区 | 队列越大越能削峰但越容易积压、延迟升高 |
| threadFactory | 造线程(命名/守护/优先级) | 影响排障可读性 |
| handler | 队列满且线程满怎么办 | 决定丢/阻塞/报错 |
二、提交一个任务的完整流程
bash
提交任务
├─ 运行线程 < corePoolSize? → 新建核心线程执行
├─ 否则队列没满? → 入队等待
├─ 队列满且线程 < maxPoolSize? → 新建非核心线程执行
└─ 队列满且线程 == maxPoolSize? → 执行拒绝策略注意顺序是「先占满核心线程 → 再入队 → 队列满才扩容到最大线程」,所以用无界 LinkedBlockingQueue 时 maximumPoolSize 永远用不上(队列永远不满)。
四种拒绝策略:
| 策略 | 行为 | 适用 |
|---|---|---|
| AbortPolicy(默认) | 抛 RejectedExecutionException | 让调用方感知过载、及时告警 |
| CallerRunsPolicy | 由提交任务的线程自己执行 | 反压、降速,不丢任务 |
| DiscardPolicy | 静默丢弃新任务 | 允许丢失的次要任务 |
| DiscardOldestPolicy | 丢队首旧任务再试 | 只要最新数据(慎用) |
三、Executors 的坑(阿里规约禁用)
newFixedThreadPool/newSingleThreadExecutor:用无界 LinkedBlockingQueue,任务堆积可 OOM。newCachedThreadPool:最大线程 Integer.MAX_VALUE,可创建海量线程导致 OOM/系统线程耗尽。- 所以要手动 new ThreadPoolExecutor,给队列和最大线程设明确边界,并自定义带业务名的 ThreadFactory(jstack 才能一眼认出)。

四、线程数怎么设
- CPU 密集型(计算、编解码):线程数 ≈ CPU 核数 + 1,多了只会增加上下文切换。
- IO 密集型(RPC、查库、等响应):线程数 ≈
核数 × (1 + IO等待时间/计算时间),实践中常见 2N、或用压测找拐点;也可上虚拟线程(Java 21)大幅简化。 - 混部/多池要考虑整体 CPU 与下游连接池容量,线程池不是越大越好。
- 优雅关闭:先
shutdown()停止接单,awaitTermination等存量结束,再shutdownNow()处理剩余。
坑
- 无界队列 + 默认拒绝:表面不报错,任务无限堆积直到 OOM,监控要盯队列大小和活跃线程数。
- 所有服务共用一个大池:一个慢接口占满线程拖垮全部功能,按业务/下游做舱壁隔离(多池)。
- 提交任务吞异常:
execute内未捕获异常只打印,submit的异常藏在 Future 里不取就消失;要 try/catch 或看 Future。 - ThreadLocal 在线程复用下串数据:线程归还前必须 remove,否则下个任务读到上个用户的数据。
- 线程数拍脑袋设 200/500:脱离任务类型和压测,过大的池在高峰引发更严重的上下文切换与内存压力。
总结
ThreadPoolExecutor 按「核心线程→有界队列→扩容到最大线程→拒绝策略」处理任务,七参数中最关键是用有界队列、合理的 core/max、带业务名的线程工厂和能反压或报错的拒绝策略;Executors 的 Fixed/Cached 因无界队列或无界线程会 OOM 应禁用;线程数上 CPU 密集取核数+1、IO 密集按等待/计算比放大并用压测定标,配合分业务池隔离、监控队列与活跃数、关闭时清理 ThreadLocal。 线程阻塞的现场见 jstack 线程栈。