千万短信1小时发完,怎么设计线程池
生产环境绝对不能用Executors快速创建线程池,不管是用new fixedThreadPool还是newCachedThreadPool,底层都是无界队列,瞬间就能撑爆jvm堆内存,生产上必须手动地去new ThreadPoolExecutor,配上有界队列,这个才是铁律,接下来,线程数到底给多少,要先了解这个任务是CPU密集型还是IO密集型,短线涉及网络调用,典型的是IO密集型,根据实战经验,IO密集型初始线程数可以按N乘以1加W比C来做基础,N就是CPU核数,W就是等待时间,C是计算时间,实际落地的时候,先设计一个初始值,通过压测不断去调优,用数据去说话,这才是架构师严谨的逻辑,拒绝策略怎么选,线程池满了,默认用abortpolicy,直接抛异常,数据丢了,绝对不能忍,生产环境下,推荐CallerRunsPolicy,它是让提交任务主线程自己去执行,这其实是一种天然的背压机制,主线程忙着发短信,就没空再去拉新任务,减缓了任务的生产速度,给线程池留出了喘息的空间,系统才不会雪崩。还有一点,线程池参数写死了,线上流量波动该怎么办,接入动态线程池,核心线程数、队列大小全部放在配置中心,实时可调,再配合一个监控报警,队列积压超过80%的时候,就自动报警,必要时候可以动态扩容,hip for g 或者 Daniel TP让人知道你有实战经验。最后千万级短信,光靠线程池绝对不够,还需要兜底,每条短信对应数据库的一条记录,设置一个状态位,发送成功直接改状态,万一服务挂了,重启后,定时任务扫描未发送的记录,补偿重发。
AI总结:
生产环境线程池的设计核心是可控性、可观测、可兜底,绝对不能直接用 Executors 快速创建线程池,必须基于 ThreadPoolExecutor 做定制化构建,配合参数科学调优、动态管控和兜底补偿机制,才能保障高并发场景下的系统稳定性。
一、为什么禁用 Executors 快速创建线程池
Executors 提供的快捷方法本质都是「无界设计」,生产环境没有流量边界管控,极易引发 OOM 和系统雪崩,核心问题分两类:
newFixedThreadPool:核心线程数与最大线程数固定,底层使用无界的LinkedBlockingQueue(默认容量Integer.MAX_VALUE)。高并发下任务会无限堆积在队列中,很快撑满 JVM 堆内存,最终触发 OOM。newCachedThreadPool:核心线程数为 0,最大线程数无界(Integer.MAX_VALUE),任务到来就创建新线程。高并发下会瞬间创建大量线程,耗尽系统 CPU 和内存资源。
生产铁律:必须手动 new ThreadPoolExecutor,显式指定所有核心参数,强制使用有界队列,从根源控制任务堆积的上限。
二、核心线程数的科学设定方法
线程数不是拍脑袋定的,要先按任务类型做估算,再通过压测最终确认。
- 先区分任务类型
- CPU 密集型:以计算逻辑为主,线程数推荐约等于 CPU 核心数,避免过多上下文切换损耗性能。
- IO 密集型:涉及网络调用、数据库读写等(比如短信发送、远程接口调用),线程大部分时间在等待 IO,CPU 利用率低,可以设置更多线程。绝大多数业务场景都属于 IO 密集型。
- IO 密集型经验公式
初始估算公式:线程数 = CPU核心数 × (1 + 等待时间 / 计算时间)- W:任务的 IO 等待时间;C:任务的 CPU 计算时间
- 例:一次短信发送,网络 IO 耗时 200ms,本地计算耗时 10ms,8 核 CPU 下,初始线程数 ≈ 8 × (1 + 200/10) = 168
- 落地原则
公式只用来估算初始值,最终参数必须通过压测验证,结合 CPU 利用率、吞吐量、响应时间逐步调优,用实际数据定最终值,这才是架构师的严谨逻辑。
三、拒绝策略的生产级选型
线程池满载(核心线程占满、队列排满、达到最大线程数)时,拒绝策略直接决定系统的稳定性。
- 默认
AbortPolicy:直接抛出拒绝异常,任务直接丢弃。生产环境绝大多数业务不能接受数据丢失,不推荐使用。 - 生产推荐:
CallerRunsPolicy(调用者运行策略)- 机制:任务提交失败时,由提交任务的主线程自己执行该任务。
- 本质是天然的背压机制:主线程忙着执行任务,就无法继续拉取、提交新任务,自动降低任务流入速度,给线程池留出喘息空间,避免任务雪崩。
四、生产级增强:动态调优与可观测性
解决参数写死、无法适配流量波动的问题,体现线上运维实战能力。
- 参数动态热更新:把核心线程数、最大线程数、队列容量等核心参数接入配置中心(如 Nacos、Apollo),支持实时调整,无需重启服务,快速应对流量波动。
- 监控告警:监控线程池的活跃线程数、队列积压率、任务拒绝次数等核心指标;队列使用率超过 80% 时自动告警,提前感知风险。
- 动态线程池:可以基于开源动态线程池组件(如 DynamicTp)实现,支持根据流量自动弹性扩缩容,适配流量波峰波谷,提升资源利用率。
五、海量任务场景的兜底补偿
千万级短信这类海量异步任务,单靠线程池无法 100% 保障可靠性,必须增加持久化兜底机制:
每条短信先落库,设置独立的状态位(待发送、发送成功、发送失败);发送成功后异步更新状态。
一旦服务异常重启,通过定时任务扫描所有「待发送 / 发送失败」的记录,执行补偿重发,保证业务最终一致性。
总结
生产环境线程池的完整设计逻辑是:先做边界管控(有界队列防 OOM)→ 科学估算参数 → 合理选择拒绝策略(背压防雪崩)→ 动态可观测适配流量 → 持久化兜底保最终一致,从基础规范到极端保障,形成完整的稳定性闭环。

浙公网安备 33010602011771号