线程池和线程池常见的参数

核心线程数(固定不销毁)、最大线程数(阻塞队列满了之后创建临时救场的线程,用完就销毁|最大线程数=核心线程数+临时线程数)、阻塞队列(暂时存储任务,决定线程池吞吐能力)、拒绝策略(阻塞队列满了而且最大线程数也到了,对后续的任务所采用的策略)

java.util.concurrent.ThreadPoolExecutor中,线程池的运作由 7 个核心参数严格控制

7个核心参数

1. corePoolSize (核心线程数)

  • 定义:线程池中常驻的“正式工”数量。
  • 逻辑即便这些线程处于空闲状态,也不会被销毁(除非显式开启了 allowCoreThreadTimeOut)。当新任务提交时,只要当前运行的线程数小于设定值,就会直接创建新线程来执行任务。

2. maximumPoolSize (最大线程数)

  • 定义:线程池能够容纳的最大并发线程极限(核心线程 + 非核心线程)。
  • 逻辑只有当阻塞队列(workQueue)被塞满时,线程池才会开始创建超出 corePoolSize 的“临时工”线程来救场,直到总数达到 maximumPoolSize

3. keepAliveTime & unit (空闲存活时间及单位)

  • 定义:非核心线程空闲等待新任务的最长时间。
  • 逻辑:当线程池中的线程数量超过 corePoolSize 时,如果这些多出来的“临时工”线程闲置时间超过了该设定值,就会被内核回收,以释放系统资源。

4. workQueue (工作队列 / 阻塞队列)

  • 定义:用于缓冲等待执行任务的并发安全队列。这是决定线程池吞吐能力与内存安全的关键。
  • 工程陷阱:在开发承受高并发流量的底层服务(如服务端 RPC 节点接收密集请求)时,绝对禁止使用无界队列(如默认容量为 Integer.MAX_VALUELinkedBlockingQueue)。一旦遇到突发流量或下游处理变慢,无限堆积的任务会迅速耗尽 JVM 堆内存,直接引发 OOM。必须使用有界队列(如 ArrayBlockingQueue)进行硬性物理拦截。

5. threadFactory (线程工厂)

  • 定义:用于定制线程创建逻辑的工厂接口。
  • 工程规范:严禁使用默认工厂(产出如 pool-1-thread-1 这样毫无语义的名称)。必须通过自定义工厂为线程赋予具有业务含义的名称(例如 rpc-provider-worker-%d)。如果不强制命名,当在 Linux 环境下通过 top -H 定位 CPU 飙升的底层线程,或通过 jstack 抓取堆栈快照排查死锁时,根本无法分辨异常线程属于哪个业务模块。

6. handler (拒绝策略)

  • 定义:当线程数达到 maximumPoolSizeworkQueue 也已满时,针对继续涌入的新任务所采取的阻断机制。
  • 默认策略
    1. AbortPolicy(默认):直接抛出 RejectedExecutionException 异常。
    2. CallerRunsPolicy:将任务退回给调用者,由提交任务的当前线程(如 Netty 的 IO 线程)直接执行。注意:这会阻塞调用方的上游线程,可能导致网络吞吐量断崖式下跌。
    3. DiscardPolicy:静默丢弃任务,不抛出异常。
    4. DiscardOldestPolicy:丢弃队列头部滞留最久的老任务,将新任务强行塞入。
  • 定制化:在严谨的系统设计中,通常需要实现自定义拒绝策略,例如将溢出的请求参数持久化到日志或消息队列中,或者向客户端返回特定的限流/降级响应报文。

线程池复用原理(Worker任务循环)

java.util.concurrent.ThreadPoolExecutor中,线程池的运作由 7 个核心参数严格控制

7个核心参数

1. corePoolSize (核心线程数)

  • 定义:线程池中常驻的“正式工”数量。
  • 逻辑即便这些线程处于空闲状态,也不会被销毁(除非显式开启了 allowCoreThreadTimeOut)。当新任务提交时,只要当前运行的线程数小于设定值,就会直接创建新线程来执行任务。

2. maximumPoolSize (最大线程数)

  • 定义:线程池能够容纳的最大并发线程极限(核心线程 + 非核心线程)。
  • 逻辑只有当阻塞队列(workQueue)被塞满时,线程池才会开始创建超出 corePoolSize 的“临时工”线程来救场,直到总数达到 maximumPoolSize

3. keepAliveTime & unit (空闲存活时间及单位)

  • 定义:非核心线程空闲等待新任务的最长时间。
  • 逻辑:当线程池中的线程数量超过 corePoolSize 时,如果这些多出来的“临时工”线程闲置时间超过了该设定值,就会被内核回收,以释放系统资源。

4. workQueue (工作队列 / 阻塞队列)

  • 定义:用于缓冲等待执行任务的并发安全队列。这是决定线程池吞吐能力与内存安全的关键。
  • 工程陷阱:在开发承受高并发流量的底层服务(如服务端 RPC 节点接收密集请求)时,绝对禁止使用无界队列(如默认容量为 Integer.MAX_VALUELinkedBlockingQueue)。一旦遇到突发流量或下游处理变慢,无限堆积的任务会迅速耗尽 JVM 堆内存,直接引发 OOM。必须使用有界队列(如 ArrayBlockingQueue)进行硬性物理拦截。

5. threadFactory (线程工厂)

  • 定义:用于定制线程创建逻辑的工厂接口。
  • 工程规范:严禁使用默认工厂(产出如 pool-1-thread-1 这样毫无语义的名称)。必须通过自定义工厂为线程赋予具有业务含义的名称(例如 rpc-provider-worker-%d)。如果不强制命名,当在 Linux 环境下通过 top -H 定位 CPU 飙升的底层线程,或通过 jstack 抓取堆栈快照排查死锁时,根本无法分辨异常线程属于哪个业务模块。

6. handler (拒绝策略)

  • 定义:当线程数达到 maximumPoolSizeworkQueue 也已满时,针对继续涌入的新任务所采取的阻断机制。
  • 默认策略
    1. AbortPolicy(默认):直接抛出 RejectedExecutionException 异常。
    2. CallerRunsPolicy:将任务退回给调用者,由提交任务的当前线程(如 Netty 的 IO 线程)直接执行。注意:这会阻塞调用方的上游线程,可能导致网络吞吐量断崖式下跌。
    3. DiscardPolicy:静默丢弃任务,不抛出异常。
    4. DiscardOldestPolicy:丢弃队列头部滞留最久的老任务,将新任务强行塞入。
  • 定制化:在严谨的系统设计中,通常需要实现自定义拒绝策略,例如将溢出的请求参数持久化到日志或消息队列中,或者向客户端返回特定的限流/降级响应报文。

线程池复用原理(Worker任务循环)

情况说明
核心线程 + 队列空默认调 take()永久阻塞等待,不退出
非核心线程 + 队列空poll(keepAliveTime)超时还没任务就返回 null → 线程退出
allowCoreThreadTimeOut = true核心线程也会超时退出
线程池被 shutdown()中断空闲线程,getTask() 返回 null
  1. task.run() 而不是 task.start()——直接在当前 Worker 线程里执行任务的 run 方法,不会创建新线程
  2. getTask() 从阻塞队列取任务。队列空了线程就阻塞等待take()),不是销毁
  3. 整个 Worker 线程的生命周期就是这个 while 循环,循环不结束,线程就一直活着

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值