跳到正文
Elaine Blog
返回

ThreadPoolExecutor 参数、拒绝与动态调节

并发编程

线程池参数必须共同解释。提交任务时,ThreadPoolExecutor 先补到核心线程数,再进入队列,队列满后才增加到最大线程数, 最后执行拒绝策略。使用无界队列时,maximumPoolSize 通常不会生效。

Table of contents

Open Table of contents

运行饱和实验

下载线程池饱和样例下载, 运行:

java -cp target/classes dev.elaine.concurrency.ThreadPoolSaturationSample

实验只有一个工作线程和一个队列槽。第一项任务占住线程,第二项排队,第三项被拒绝,输出 拒绝任务数=1。Latch 让时序 确定,不依赖 sleep 猜测线程是否已经启动。

五个核心参数

参数决定什么常见风险
corePoolSize稳态保留工作线程过大增加上下文切换
maximumPoolSize队列满后的线程上限无界队列下几乎无效
workQueue等待容量与顺序过大隐藏过载并增加延迟
keepAliveTime非核心空闲线程回收过短导致频繁创建
RejectedExecutionHandler饱和时怎样失败静默丢任务或阻塞关键线程

线程工厂应设置可识别名称和未捕获异常处理器。任务内部抛出的异常若被 Future 捕获,不一定到达未捕获异常处理器;必须 观察任务失败指标。

按任务模型估算线程数

CPU 密集任务的线程数通常接近可用核心数。阻塞任务可使用更多线程,但上限仍受下游容量、内存和延迟预算约束。一个常见 起点是:

线程数 ≈ CPU 核数 × 目标利用率 × (1 + 等待时间 / 计算时间)

它只是测量起点,不是配置公式。等待时间分布、容器 CPU 配额、下游连接池和任务优先级都会改变结果。

拒绝策略是业务协议

不要在自定义拒绝器中无限阻塞;这会把线程池拥塞扩散到上游并制造级联故障。

动态调节需要闭环

setCorePoolSize 等 API 可以在线修改参数,但控制器要有采样窗口、上下限、冷却时间和回滚。监控活跃线程、队列深度、 任务年龄、拒绝率、执行时间和下游饱和度。只根据 CPU 自动加线程会把数据库压垮。

下一步

阅读Future 与 CompletableFuture 异步编排,为线程池任务增加 结果、超时、异常和取消协议。


分享这篇文章:

上一篇
BlockingQueue 与生产者消费者
下一篇
Future 与 CompletableFuture 异步编排