生产环境必须手动创建threadpoolexecutor,禁用executors工厂方法;因其默认线程池使用无界队列或无限线程数,易导致oom;需按cpu/io密集型合理设核心与最大线程数,选用有界队列,配置可观察拒绝策略,并配套命名、监控与优雅关闭机制。

生产环境用线程池,核心就一条:不靠默认,全靠可控。
必须手动创建,禁用Executors工厂方法
Executors.newFixedThreadPool、newCachedThreadPool等方法隐藏严重风险:
- newFixedThreadPool 内部用的是无界LinkedBlockingQueue,任务积压会OOM
- newCachedThreadPool 允许无限创建线程,突发流量下可能瞬间创建数万线程,直接拖垮JVM
- newSingleThreadExecutor 同样使用无界队列,单点故障+堆积风险并存
正确做法是显式构造ThreadPoolExecutor,所有参数清晰可见、可监控、可审计。
参数配置要贴合业务特征
没有通用值,只有匹配场景的合理值:
- CPU密集型任务(如图像压缩、加解密):corePoolSize = CPU核数 + 1;maximumPoolSize 可设为相同值,避免上下文切换损耗
- IO密集型任务(如HTTP调用、DB查询):corePoolSize ≈ CPU核数 × (1 + 平均等待时间 / 平均CPU执行时间),常见取值为核数×2~5;maximumPoolSize 可设为 core × 2~3
- workQueue 必须有界:优先选ArrayBlockingQueue,容量建议设为最大线程数的2~3倍;避免用LinkedBlockingQueue(即使设了容量,也易被忽略)
拒绝策略不能用默认,要可观察、可兜底
AbortPolicy(抛异常)在生产中等于“静默失败”,应替换为更稳妥的策略:
- CallerRunsPolicy:让提交线程自己执行,天然限流,适合下游能承受短时压力的场景
- 自定义拒绝策略:记录日志 + 上报监控 + 落库重试(如秒杀未提交订单写入延迟队列)
- 绝对避免丢弃关键任务(DiscardPolicy)或仅丢最老任务(DiscardOldestPolicy),除非明确业务允许
配套机制一个都不能少
线程池不是孤立组件,需嵌入可观测与治理体系:
- 命名规范:通过ThreadFactory设置有意义线程名,如“order-processor-pool-%d”,便于堆栈定位
- 主动关闭:应用停机前调用shutdown() + awaitTermination(),避免任务丢失或线程泄漏
- 指标暴露:通过ThreadPoolExecutor的getActiveCount()、getQueue().size()等方法接入Prometheus或自建监控看板
- 动态调整(进阶):结合配置中心(如Nacos)支持运行时调整corePoolSize、maxPoolSize,应对流量峰谷
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











