线程数需依任务类型、资源瓶颈和压测数据确定:纯计算型≈CPU核数;IO密集型按等待/CPU耗时比估算;须检查CPU饱和、内存栈空间、下游连接池等硬约束;队列策略影响弹性,禁用无界队列;上线后依监控动态调优。

核心线程数和最大线程数不能靠经验公式直接套用,必须结合任务行为、资源瓶颈和实际压测数据来定。盲目设成 CPU核数+1 或 2倍CPU核数 在真实业务中经常失效。
先判断任务类型,再估算理论下限
不是简单分“CPU型”或“I/O型”,而是看单个任务里CPU计算时间和阻塞等待时间的比例:
- 纯计算(如加解密、图像缩放):几乎无等待 → 核心线程数 ≈ CPU核心数,最大线程数可等于核心数
- 数据库查询(含网络+锁+磁盘):等待远大于计算 → 核心线程数建议从
CPU核心数 × (1 + 平均等待毫秒 / 平均CPU耗时毫秒)起步 - 调用多个下游HTTP接口:等待分散、连接池受限 → 线程数上限常被
HTTP客户端最大连接数卡住,而非CPU
必须检查系统级硬约束
再合理的理论值,撞上资源红线也会崩:
-
CPU饱和点:用
top -H或pidstat -t观察线程级CPU使用率,持续 >90% 就说明线程已超负荷 -
内存够不够:每个线程默认栈空间约1MB(
-Xss1m),500个线程就占0.5GB堆外内存,容器环境尤其要留余量 -
下游水位:DB连接池是否打满?Redis连接是否超时?HTTP客户端是否频繁
Connection refused?这些才是线程数的实际天花板
队列策略决定线程数的弹性空间
线程数不是孤立配置的,它和队列类型强耦合:
立即学习“Java免费学习笔记(深入)”;
- 用
SynchronousQueue:队列容量为0,任务不排队,直接触发扩容 → 最大线程数必须足够覆盖峰值并发,否则大量拒绝 - 用
ArrayBlockingQueue(比如容量200):队列能缓冲突发,核心线程数可保守些,最大线程数可设为核心数的1.5~2倍 - 禁用
LinkedBlockingQueue(无界):最大线程数形同虚设,高负载下易 OOM,除非你明确接受任务无限堆积
上线后靠监控动态调优
初始值只是起点,关键看运行时指标:
- 活跃线程数长期
- 队列长度持续 >70% 容量 → 说明任务入队多、执行慢,要么优化单任务耗时,要么适当增大队列或核心数
- 频繁触发拒绝策略(尤其
AbortPolicy)→ 不是立刻加最大线程数,先查是不是下游响应变慢或超时设置过短 - 线程数在 core 和 max 之间反复伸缩 → keepAliveTime 太短,可延长到60~120秒减少抖动


















