threadpoolexecutor 参数需按任务类型、资源与流量科学配置:cpu密集型设corepoolsize为cpu核数+1,i/o密集型设为核数×2~4;必须用有界队列;keepalivetime建议60秒并配callerrunspolicy拒绝策略;须自定义threadfactory和handler。

ThreadPoolExecutor 的核心参数不能靠经验拍脑袋,得按任务类型、系统资源和流量特征来配。配错轻则响应变慢,重则内存溢出或线程爆炸。
corePoolSize 和 maximumPoolSize 要分场景算
这两个数不是随便填的,得看任务是 CPU 密集型还是 I/O 密集型:
- CPU 密集型(如图像压缩、复杂计算):核心线程数建议设为 CPU 核心数 + 1,最大线程数可略高一点,比如 +2 或 +3,避免 CPU 空转
- I/O 密集型(如数据库查询、HTTP 调用):线程常在等响应,可设为 CPU 核心数 × 2~4,最大线程数建议不超过核心数的 3 倍,防止上下文切换开销过大
- 别用
Runtime.getRuntime().availableProcessors()直接当核心数——它返回的是逻辑核数,还要结合容器限制(如 Kubernetes 中的 CPU limit)做折算
workQueue 必须是有界队列
无界队列(比如 new LinkedBlockingQueue())是线上事故高发区:
- 队列无限大 → 任务永远能塞进去 →
maximumPoolSize失效 → 非核心线程永不创建 → 拒绝策略永远不会触发 - 结果就是任务越堆越多,内存持续上涨,最终 OOM 或接口雪崩
- 推荐用
new ArrayBlockingQueue(128)或new LinkedBlockingQueue(256),容量根据平均 QPS 和任务处理时长估算(例如:QPS=100,平均耗时 200ms,缓冲 20~50 个任务较安全)
keepAliveTime 和拒绝策略要配套选
空闲时间不是越大越好,拒绝策略也不能只用默认:
-
keepAliveTime设 60 秒比较通用;若业务波动大,可配合allowCoreThreadTimeOut(true)让核心线程也支持回收 - 拒绝策略优先选
CallerRunsPolicy:过载时让调用线程自己执行任务,天然限流,还能避免丢任务 - 慎用
AbortPolicy(默认):抛异常容易被上层吞掉,问题难发现;DiscardPolicy更危险,静默丢任务可能引发数据不一致
threadFactory 和 handler 要显式配置
看似可选,实则影响可观测性和稳定性:
- 自定义
ThreadFactory给线程起名,比如"biz-upload-pool-%d",出问题时从线程 dump 里一眼定位来源 - 拒绝策略别省略,必须显式传参;handler 是最后防线,没它等于没熔断
- 不要用
Executors.newFixedThreadPool()或newCachedThreadPool()—— 阿里规范禁用,源码里藏着无界队列或无限线程数的坑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











