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() 会创建新线程补充核心线程数
  • 核心线程数不会因异常全部消失
相关推荐
Gofarlic_oms14 小时前
利用API实现ANSYS许可证管理自动化集成
运维·服务器·开发语言·matlab·自动化·负载均衡
AI+程序员在路上5 小时前
VS Code 完全使用指南:下载、安装、核心功能与 内置AI 编程助手实战
开发语言·人工智能·windows·开源
invicinble5 小时前
这里对java的知识体系做一个全域的介绍
java·开发语言·python
catchadmin5 小时前
使用 PHP TrueAsync 改造 Laravel 协程异步化的可行路径
开发语言·php·laravel
wbs_scy5 小时前
【Linux 线程进阶】进程 vs 线程资源划分 + 线程控制全详解
java·开发语言
ss2736 小时前
食谱推荐系统功能测试如何写?
java·数据库·spring boot·功能测试
AI人工智能+电脑小能手6 小时前
【大白话说Java面试题】【Java基础篇】第15题:JDK1.7中HashMap扩容为什么会发生死循环?如何解决
java·开发语言·数据结构·后端·面试·哈希算法
m0_674294646 小时前
如何编写SQL存储过程性能对比_记录执行时间评估优化效果
jvm·数据库·python
try2find6 小时前
打印ascii码报错问题
java·linux·前端
014-code6 小时前
CompletableFuture 实战模板(超时、组合、异常链处理)
java·数据库