cpu核心数是最优corepoolsize值,因超线程数会导致上下文切换开销、吞吐下降;应动态获取逻辑核心数、禁用动态扩容、配synchronousqueue和callerrunspolicy,并监控runnable线程数与完成量验证效果。

直接设为 CPU 核心数,是最有效的方式。计算密集型任务几乎不等待、全程占 CPU,线程一多,系统就在不停切换上下文,实际算得反而更慢。
为什么不能超过核心数
每个 CPU 核心同一时刻只能执行一个线程的指令。当 corePoolSize 超过可用核心数(比如 8 核设成 16 个线程),操作系统必须轮换调度——刚把线程 A 的寄存器状态保存,立刻加载线程 B 的,再切回来……这种切换本身就要消耗 CPU 时间和缓存资源。实测中,线程数翻倍后吞吐量常不升反降,延迟反而明显升高。
- 可用核心数用 Runtime.getRuntime().availableProcessors() 获取,它返回的是逻辑核心数(含超线程)
- 不要硬编码,如
newFixedThreadPool(8),否则上线到不同配置机器就失效 - 避免设置
allowCoreThreadTimeOut(true),核心线程本该常驻,超时回收再重建反而增加开销
配套参数必须同步调优
corePoolSize 不是孤立参数。只调它,其他地方没跟上,照样卡顿或浪费资源。
- maximumPoolSize 建议等于 corePoolSize,禁止动态扩容——计算任务不该“临时加人”,否则加剧争抢
- workQueue 推荐 SynchronousQueue,它不缓存任务,直接配对线程与任务,避免堆积和虚假并发
- 拒绝策略 选 CallerRunsPolicy,让提交者自己执行,既控压又不丢任务,比 AbortPolicy 更稳
验证是否真正生效
设完不是就完了。得看线程池是不是真按预期跑满核心,有没有隐性瓶颈。
- 运行时检查:
executor.getActiveCount()应长期接近corePoolSize,若持续偏低,说明任务本身有阻塞(比如意外 IO) - 监控
executor.getCompletedTaskCount()和单位时间处理量,对比调参前后提升是否符合预期 - 用
jstack或 Arthas 抓线程栈,确认多数线程状态是 RUNNABLE,而非 WAITING 或 BLOCKED
不复杂但容易忽略:核心数是起点,不是终点;设对了 corePoolSize,只是让 CPU 跑起来的第一步。










