线程数并非越多越好,关键在于定位瓶颈:锁竞争(blocked多)、资源等待(waiting多)、调度排队(runnable多但cpu低)等;需用jstack、jmh、perf等工具实测拐点,而非依赖理论公式。

线程数不是越多越好,关键看瓶颈在哪。盲目加线程不仅不提速,反而可能让吞吐下降、延迟飙升——这在JDK 21的压测数据里已经反复验证过:300个平台线程跑10万I/O任务,比50个还慢近一倍。
看线程状态分布,快速定位阻塞点
用 jstack 抓一次线程快照,重点扫三类状态:
-
BLOCKED多 → 锁竞争严重,比如synchronized方法或ReentrantLock争抢频繁 -
WAITING/TIMED_WAITING多且集中在park、wait或Thread.sleep→ 线程在等资源(数据库连接、远程响应、队列取空),不是CPU瓶颈 -
RUNNABLE多但CPU没打满 → 可能是伪RUNNABLE(实际在等OS调度),或代码有隐式同步(如String.intern()、ClassLoader.loadClass())
注意:RUNNABLE 不等于“正在跑”,它包含“就绪排队中”。如果 top 显示 CPU 使用率低,但大量线程卡在 RUNNABLE,基本可以断定是调度器排队,而不是计算密集。
用 JMH 测真实吞吐拐点,别信“理论核心数”
平台线程的收益衰减非常陡峭,靠公式(比如 CPU核心数 × (1 + 平均等待时间/平均计算时间))估算容易翻车。实操建议:
- 写一个带可控线程池的 JMH 测试,用
@Fork隔离 JVM 实例,避免干扰 - 固定任务类型(比如模拟 DB 查询的
Thread.sleep(5)+ 小量计算),只变corePoolSize - 每组测试跑 5 轮
@Measurement,观察Score Error是否稳定;一旦误差 >15%,说明结果已不可信 - 画出“线程数-吞吐量”曲线,拐点往往出现在吞吐增速跌破 5%/新增线程时
示例中,从 8 线程升到 16 线程,吞吐只涨 3.2%,再升到 32 线程反而降 1.8%——这时加线程就是纯开销。
虚拟线程下,“线程数”概念本身失效
Java 21 的 Executors.newVirtualThreadPerTaskExecutor() 不需要你手动调参线程数。它的性能拐点不在“多少个线程”,而在:
-
java.lang.VirtualThread的调度延迟是否开始上升(用ThreadMXBean.getThreadAllocatedBytes()监控分配速率) - GC 压力是否突增(ZGC 下
Allocation Rate> 500MB/s 就要警惕) - 系统调用次数是否暴涨(
perf stat -e syscalls:sys_enter_futex查 futex 争用)
这时候该优化的是 I/O 路径(比如把 FileInputStream 换成 AsynchronousFileChannel),而不是继续堆虚拟线程。
真正难的不是算出“该用多少线程”,而是分清当前瓶颈是调度器排队、锁竞争、内存带宽、还是系统调用。这些信号藏在线程状态、GC 日志和 perf 数据里,不在公式里。











