关键在于建立“可感知、可控制、可隔离”的执行边界:必须用有界队列+反压型拒绝策略,参数贴合业务类型,多业务线程池隔离,并通过监控及时告警。

避免线程资源耗尽,关键不是堆大线程数,而是建立“可感知、可控制、可隔离”的执行边界。核心在于用有界队列触发主动拒绝,靠合理参数匹配业务特征,并通过监控与隔离提前化解风险。
必须用有界队列 + 反压型拒绝策略
无界队列(如 LinkedBlockingQueue 默认构造)是资源耗尽的头号诱因——任务持续堆积,内存迟早 OOM,而线程数却卡死不动。必须显式使用容量受限的队列:
- 选 ArrayBlockingQueue(200) 或带容量的 LinkedBlockingQueue(100),容量按单任务内存占用 × 预估并发量估算
- 拒绝策略禁用默认 AbortPolicy(静默丢任务),优先用 CallerRunsPolicy:队列满时由调用线程(如 Tomcat 线程)同步执行,天然形成反压,拖慢上游提交速度
- 自定义策略更稳妥:记录任务类型、当前队列大小、提交耗时,并触发告警,不加耗时操作(如远程日志)
参数要贴合业务类型,不能拍脑袋设
线程数不是越多越好,错配反而加剧资源争抢和上下文切换开销:
- CPU 密集型(如计算、加解密):corePoolSize 设为 Runtime.getRuntime().availableProcessors() 或 +1;maximumPoolSize 不宜超过 core × 2
- I/O 密集型(如数据库查询、HTTP 调用):corePoolSize 可设为 core × 2~4,但需配合监控阻塞率,避免盲目扩容
- keepAliveTime 建议 30~60 秒,让空闲非核心线程及时释放栈内存和系统线程句柄
多业务必须做线程池隔离
一个线程池扛所有请求,等于把登录、下单、报表导出全绑在同一根绳上。某类高耗任务(如大文件解析)跑满线程,其他业务直接不可用:
立即学习“Java免费学习笔记(深入)”;
- 按业务域拆分独立线程池:例如 order-executor、notify-executor、report-executor
- 每个池配专属名称前缀(通过 ThreadFactory),方便线程 dump 时快速定位归属
- 连接池(DB、Redis)、HTTP 客户端等也需对应隔离,防止底层资源被单点打穿
监控比调参更重要,得看得见才控得住
再好的初始配置也扛不住流量突增或下游变慢。不采集指标,等于闭眼开车:
- 必看三项:活跃线程数(getActiveCount())、队列当前大小(getQueue().size())、拒绝次数(需自定义 handler 统计)
- 设置水位告警:队列使用率持续 >80% 或活跃线程长期打满,说明资源已紧绷,需扩容或优化任务逻辑
- 接入 Prometheus + Grafana,或通过 Spring Boot Actuator 暴露 /actuator/prometheus 端点


















