1204 字
6 分钟
Java 线程池:七个参数、执行流程与配置原则

线程池复用工作线程,控制并发资源。面试重点是任务先交给谁、什么时候扩容或拒绝,以及怎样避免任务无边界堆积。

七个核心参数#

参数作用
corePoolSize核心线程数,通常按需创建,也可预启动
maximumPoolSize最大线程数
keepAliveTime空闲线程保活时间
unit保活时间单位
workQueue等待任务的队列
threadFactory线程创建、命名等
handler任务无法接收时的拒绝策略

默认主要回收超过核心数量的空闲线程,启用 allowCoreThreadTimeOut 后核心线程也可超时回收。

execute 的基本流程#

提交任务
├─ 线程数不足 core:尝试创建线程直接执行
└─ 否则尝试入队
├─ 入队成功:由工作线程获取任务,并复查池状态
└─ 入队失败:尝试创建线程,直到 maximum
└─ 无法创建或池已关闭:拒绝

通常先到核心数,再入队,队列满了才扩展到最大数。 不是先把线程开到最大才排队。关闭竞态等状态检查属于实际实现必要步骤,基础面试不必逐行背。

无界队列持续接收任务时,maximumPoolSize 通常难以起到扩容作用,积压可能耗尽内存。SynchronousQueue 不保存普通排队任务,而是尝试直接交接。

四种常见拒绝策略#

  • AbortPolicy:抛 RejectedExecutionException,默认策略。
  • CallerRunsPolicy:池未关闭时由提交线程执行,形成反馈;提交方是请求线程时会增加请求延迟。
  • DiscardPolicy:丢弃任务。
  • DiscardOldestPolicy:通常丢弃队列头部任务,再尝试提交,有丢失任务和队列语义限制。

必须处理的业务不能静默丢弃。CallerRunsPolicy 也不是无损队列,池关闭时不会继续执行被拒绝任务。

Executors 常见工厂有什么风险?#

这些工厂方便创建线程池,但要知道默认边界,不是所有场景都禁止使用 Executors。

工厂常见实现特点主要风险
newFixedThreadPool(n)固定线程数,使用无界 LinkedBlockingQueue生产快于消费时,任务持续堆积并占用内存
newSingleThreadExecutor()单工作线程,无界任务队列慢任务阻塞后续任务,积压没有合理的业务上限
newCachedThreadPool()SynchronousQueue 直接交接,最大线程数很大任务长时间占用线程时,可能不断创建线程耗尽资源

无界队列不代表无限内存,最大线程数很大也不代表系统能承受。固定池的问题主要是排队增长,Cached 池的问题主要是线程增长,两者不要混淆。

需要明确资源预算的服务通常显式构造 ThreadPoolExecutor:限制队列和最大并发,配上合适拒绝策略、线程命名与监控。其他池有自己的模型,不能把这张表套到所有 Executors 工厂。

怎样配置线程数?#

CPU 密集任务以可用 CPU 核数附近为起点;阻塞 IO 任务可能用更多线程,但必须考虑数据库连接数、下游容量、响应时间和内存。没有脱离工作负载的最佳公式。

ExecutorService pool = new ThreadPoolExecutor(
4, 8, 30, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);

这是参数关系示例,不是线上通用配置。实际应命名线程,监控活跃线程、排队量、耗时和拒绝次数,通过压测调整,必要时按任务类型隔离线程池。

execute、submit 与关闭#

execute 提交 Runnable,没有返回 Future;submit 返回 Future。submit 的任务异常通常由 Future 保存,调用 get 时通过 ExecutionException 暴露,不读取结果可能漏掉失败。

shutdown 停止接收新任务,继续处理已接收任务;shutdownNow 尝试中断工作线程,返回尚未开始的排队任务,不保证运行中的任务一定停止。任务还需要正确响应取消和超时。

面试回答模板#

线程池的七个参数包括核心数、最大数、保活时间与单位、队列、线程工厂和拒绝策略。通常先创建核心线程,再排队,队列满后扩展到最大数,仍无法处理就拒绝。配置要结合任务类型和下游容量,限制积压并监控拒绝,不能靠无界队列和大最大线程数解决所有问题。

自测#

  1. 核心线程正在忙、队列还没满时,通常先排队还是开非核心线程?先排队。
  2. 无界队列配大 maximum 能解决积压吗?不能。
  3. submit 后不读取 Future 有什么风险?任务异常可能被忽略。
  4. Fixed 和 Cached 池的主要资源风险一样吗?不一样,前者主要是任务积压,后者可能是线程数量增长。
Java 线程池:七个参数、执行流程与配置原则
https://blog.xqcherry.top/posts/interview/java/thread-pool-basics/
作者
xqcherry
发布于
2026-10-12
许可协议
CC BY-NC-SA 4.0