线程池优化关键在于匹配缓冲能力与真实吞吐,而非盲目增大线程数;cpu密集型用synchronousqueue+cpu核数+1线程+callerrunspolicy;io密集型用arrayblockingqueue(20~50)+cpu×2~10线程;混合型按峰值tps×平均耗时/1000估算队列,且必须用有界队列并监控活跃线程与队列余量。

任务堆积不是线程池“不够大”,而是队列长度、线程数和任务节奏没对齐。关键在让缓冲能力匹配真实吞吐,而不是堆参数。
CPU密集型:少线程 + 小队列 + 不缓存
CPU几乎满负荷运转,线程没空等IO,多开线程只会加剧上下文切换。此时队列不是用来“存任务”,而是防偶发抖动。
- 用 SynchronousQueue(容量为0),任务来了必须立刻被线程消费
- corePoolSize = maximumPoolSize = CPU核数 + 1
- 拒绝策略建议用 CallerRunsPolicy —— 让提交线程自己执行,天然限流
I/O密集型:适度扩容 + 短队列 + 优先起线程
线程常卡在等待网络或数据库响应,CPU有余力,但队列不能太大,否则积压吃内存。
- corePoolSize ≈ CPU核数 × 2,maximumPoolSize ≈ CPU核数 × 8~10
- 队列容量设为 20~50(非无界!);任务先入队,队满再扩容线程
- 避免 LinkedBlockingQueue() 默认无界写法,改用 ArrayBlockingQueue(50)
混合型或业务型:按TPS和耗时反推队列
比如订单创建含校验、调用三方、写库三段,每段耗时不一,不能只看CPU或IO单一定性。
- 队列大小 ≈ 峰值TPS × 平均单任务耗时(毫秒) ÷ 1000
- 例:峰值每秒500单,平均耗时60ms → 理论缓冲30个,实际设64(留余量)
- corePoolSize 可取 CPU×1.5,maximumPoolSize 取 CPU×3,后续靠压测调优
有界是底线,监控是常态
无界队列等于把背压交给JVM堆内存,一旦下游变慢,OOM就在几秒内发生。
- 一律禁用 LinkedBlockingQueue() 无参构造;必须显式指定容量
- 上线后盯两个指标:活跃线程数(是否长期打满)、队列剩余容量(是否持续低于20%)
- 配合 Prometheus 或 Spring Boot Actuator 暴露 /actuator/pools,发现堆积及时告警
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











