Java 线程池 — ThreadPoolExecutor

一、线程池基础概念

1. 核心定义

线程池:基于池化思想管理线程的工具,维护多个线程等待分配任务,避免线程创建 / 销毁的开销,控制线程数量防止资源耗尽。

2. 核心优势

  • 降低资源消耗:复用线程,减少创建 / 销毁损耗
  • 提高响应速度:任务到达无需等待线程创建
  • 提升可管理性:统一分配、调优和监控线程资源
  • 扩展功能丰富:支持定时 / 周期性任务(如 ScheduledThreadPoolExecutor)

二、线程池创建方式

1. 推荐方式:ThreadPoolExecutor 构造器

核心构造方法
复制代码
public ThreadPoolExecutor(
    int corePoolSize,        // 核心线程数
    int maximumPoolSize,     // 最大线程数
    long keepAliveTime,      // 非核心线程空闲存活时间
    TimeUnit unit,           // 存活时间单位
    BlockingQueue<Runnable> workQueue,  // 任务队列
    ThreadFactory threadFactory,        // 线程工厂
    RejectedExecutionHandler handler    // 拒绝策略
)
核心参数详解
参数 作用 关键说明
corePoolSize 核心线程数 初始化时无线程,任务到来时创建,默认不会回收(allowCoreThreadTimeOut 可修改)
maximumPoolSize 最大线程数 核心线程 + 非核心线程的上限,队列满时才会创建非核心线程
keepAliveTime 非核心线程空闲时间 corePoolSize == maximumPoolSize 时无效
workQueue 任务缓冲队列 核心线程满时存放任务,分有界 / 无界 / 同步队列
threadFactory 线程创建工厂 默认 Executors.defaultThreadFactory (),可自定义线程名称、优先级等
handler 拒绝策略 队列和最大线程数均满时触发

2. 不推荐方式:Executors 静态方法

弊端(阿里巴巴 Java 开发手册强制要求避免)
  • FixedThreadPool/SingleThreadExecutor:队列长度为 Integer.MAX_VALUE,易堆积任务导致 OOM
  • CachedThreadPool/ScheduledThreadPool:最大线程数为 Integer.MAX_VALUE,易创建大量线程导致 OOM
Executors 线程池类型对比
类型 线程构成 核心特点 应用场景
FixedThreadPool 核心线程固定 核心线程不回收,队列无界 控制最大并发数
ScheduledThreadPool 核心 + 非核心线程 非核心线程闲置立即回收 定时 / 周期性任务
CachedThreadPool 仅非核心线程 60s 空闲回收,线程数无界 短耗时、数量多的任务
SingleThreadExecutor 1 个核心线程 任务顺序执行,无需同步 单线程串行任务(如数据库操作)

三、核心组件详解

1. 任务队列(workQueue)类型

  • ArrayBlockingQueue(有界队列):长度固定,队列满时创建非核心线程,最大线程满则触发拒绝策略
  • LinkedBlockingQueue(无界队列):长度无限,易因任务堆积导致 OOM
  • SynchronousQueue(同步队列):长度为 0,不缓存任务,直接移交线程执行

2. 拒绝策略(RejectedExecutionHandler)

策略类型 核心逻辑 适用场景
AbortPolicy(默认) 丢弃任务并抛出 RejectedExecutionException 关键业务(需及时感知异常)
DiscardPolicy 丢弃任务不抛异常 无关紧要的业务
DiscardOldestPolicy 丢弃队列最久任务,重试提交当前任务 允许丢弃老任务的场景
CallerRunsPolicy 由提交任务的主线程执行 需所有任务执行完毕的场景

四、线程池使用方法

1. 任务提交方式

方法 返回值 适用场景
execute(Runnable command) 无需返回结果的任务
submit(Runnable task) Future<?> 需判断任务是否完成
submit(Callable<T> task) Future<T> 需获取任务执行结果

2. 批量任务执行

  • invokeAll(Collection<? extends Callable<T>> tasks):等待所有任务完成,返回所有结果
  • invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit):超时取消未完成任务
  • invokeAny(Collection<? extends Callable<T>> tasks):返回第一个完成的任务结果
  • invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit):超时取消未完成任务

3. 定时 / 周期性任务(ScheduledThreadPoolExecutor)

  • schedule(Runnable/Callable task, long delay, TimeUnit unit):延时一次执行
  • scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit):固定周期执行(以上次任务开始时间计算)
  • scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit):固定间隔执行(以上次任务结束时间计算)

4. 线程池关闭

方法 核心逻辑 线程池状态
shutdown() 不接收新任务,执行完队列中任务 SHUTDOWN
shutdownNow() 不接收新任务,中断正在执行的任务,返回未执行任务 STOP
isTerminated() 所有任务执行完毕返回 true TERMINATED

关闭方法对比

五、线程池参数设计公式

1. 核心线程数(corePoolSize)

  • 公式:核心线程数 = (每秒任务数 × 单个任务执行时间)× 80%(二八原则)
  • 示例:每秒 100 个任务,单个任务 0.1 秒 → 100×0.1×0.8=8(实际取 10 优化)

2. 任务队列长度(workQueue)

  • 公式:队列长度 = 核心线程数 / 单个任务执行时间 × 2
  • 示例:核心线程数 10,单个任务 0.1 秒 → 10/0.1×2=200

3. 最大线程数(maximumPoolSize)

  • 公式:最大线程数 = (最大每秒任务数 - 队列长度)× 单个任务执行时间
  • 示例:最大每秒 1000 个任务,队列长度 200,单个任务 0.1 秒 →(1000-200)×0.1=80

4. 空闲时间(keepAliveTime)

  • 无固定公式,根据系统压力和任务间隔调整(默认 60s 可参考)

六、线程池核心原理

1. 任务执行流程

2. 线程池状态流转

线程池通过 ctl(AtomicInteger)维护状态(高 3 位)和工作线程数(低 29 位),五种状态流转如下:

3. 关键源码逻辑

(1)execute () 方法核心流程
  1. 工作线程数 < corePoolSize → 创建核心线程执行任务
  2. 线程池 RUNNING 且队列未满 → 任务入队
  3. 队列满且工作线程数 < maximumPoolSize → 创建非核心线程执行任务
  4. 队列和最大线程数均满 → 执行拒绝策略
(2)线程回收机制
  • 非核心线程:空闲时间超过 keepAliveTime 时,通过 poll(keepAliveTime) 超时回收
  • 核心线程:默认不回收,allowCoreThreadTimeOut=true 时可回收
  • 回收触发:getTask() 方法返回 null → 线程退出循环 → 执行 processWorkerExit() 善后
(3)异常处理机制
  • 任务执行抛异常 → 线程退出 → processWorkerExit() 会创建新线程补充核心线程数
  • 核心线程数不会因异常全部消失
相关推荐
晴天的雨.99213 分钟前
【C++算法】和为s的两个数
开发语言·数据结构·c++·算法
IvanCodes5 小时前
Python 数据处理(十三):JSON、CSV 与数据序列化
开发语言·python
Patrick在香港6 小时前
Claude 工具调用返回空:8 次失败里只有 1 次状态码不对,其余全带 200
爬虫·python·api·claude·香港
步行cgn6 小时前
Spring c 命名空间注入详解
java·后端·spring
Web3&Basketball6 小时前
CRM Agent 后训练实战:3 倍更少错误
python·架构·大模型·agent·推理
明月_清风7 小时前
Maven 到底是什么?一篇文章搞懂 Java 项目构建与依赖管理
java·后端·maven
aramae7 小时前
MySQL复合查询(8)
java·c语言·开发语言·后端·算法
Rain的Java大神之路7 小时前
如何快速上传10G文件
java·spring boot·redis·后端·mysql·spring cloud·面试
AIFQuant7 小时前
ETF行情API接入踩坑记:从报错到跑通的七个问题
python·金融·区块链·etf·基金
Wang's Blog8 小时前
Java 接入Redis: 通用命令与键管理
java·服务器·redis