corePoolSize应据任务类型和系统资源设定:CPU密集型设为CPU核心数,IO密集型可设为16~24;过小致排队延迟,过大增上下文切换与GC压力;需动态配置,Spring Boot中须初始化前调用setCorePoolSize()。

corePoolSize设多少才不浪费也不卡顿
这个值不是拍脑袋定的,得看任务类型和系统资源。CPU密集型任务建议设为 Runtime.getRuntime().availableProcessors(),比如8核就设8;IO密集型可以翻倍甚至更高,因为线程常在等网络或磁盘,设16~24更常见。
设太小:大量任务排队,响应延迟飙升;设太大:线程上下文切换开销剧增,GC压力也变大,反而拖慢吞吐。
- 别直接写死数字,用配置项或系统属性动态传入,方便压测调优
- Spring Boot项目常用
ThreadPoolTaskExecutor,它的setCorePoolSize()必须在初始化前调用,否则无效 - 注意JVM参数
-XX:ActiveProcessorCount可能影响availableProcessors()返回值,容器环境下尤其要核对
maximumPoolSize和workQueue怎么配才不OOM
maximumPoolSize 和 workQueue 是一对联动参数,单独调哪个都容易出事。典型错误是把 workQueue 设成无界队列(如 LinkedBlockingQueue 无参构造),再配上小的 maximumPoolSize —— 高并发时任务全堆进队列,内存直接爆掉。
推荐组合:
立即学习“Java免费学习笔记(深入)”;
- CPU密集型:用
ArrayBlockingQueue(有界),容量 ≈corePoolSize × 2~3,maximumPoolSize和corePoolSize相同或略高(+2~4) - IO密集型:可稍放宽,
maximumPoolSize设为corePoolSize × 2,队列容量控制在 100~500,避免堆积过久 - 绝对不要用
Executors.newFixedThreadPool()生产环境,它底层就是无界队列 + 固定大小,等于埋雷
keepAliveTime设太短或太长分别会怎样
这个参数只对超出 corePoolSize 的空闲线程生效。设太短(如100ms),线程刚建好就销毁,下次又要重建,频繁创建/销毁开销大;设太长(如60分钟),低峰期一堆闲置线程占着内存和句柄不放,连接池、文件句柄等资源可能被耗尽。
通用建议:
- 默认用
60L秒,单位必须是TimeUnit.SECONDS,别错用毫秒 - 如果任务有明显波峰波谷(比如定时批处理),可配合
allowCoreThreadTimeOut(true)让所有线程都可超时回收,但要注意首次请求的冷启动延迟 - Netty、Dubbo等框架内置线程池通常已调优,别盲目覆盖它们的
keepAliveTime
拒绝策略选哪个能准确定位问题
默认的 AbortPolicy 抛 RejectedExecutionException,但线上往往只记了日志没告警,问题被掩盖。真正有用的策略是 CallerRunsPolicy 或自定义策略:
-
CallerRunsPolicy让调用线程自己执行任务,会拖慢上游,但能自然限流并暴露瓶颈点——监控看到某接口RT突增,基本就是线程池撑不住了 - 自定义策略建议记录关键信息:
task.getClass().getName()、当前队列大小getQueue().size()、活跃线程数getActiveCount() - 千万别用
DiscardPolicy(静默丢弃)或DiscardOldestPolicy(丢最老的),除非你明确知道丢的是什么且可接受
线程池调优没有银弹,核心是让 getActiveCount()、getQueue().size()、拒绝次数这三项指标可采集、可告警。很多问题不是参数不对,而是根本没监控这些值。










