酒泉市网站建设_网站建设公司_Banner设计_seo优化
2025/12/22 9:47:53 网站建设 项目流程

从零开始学 Java 线程池:ThreadPoolExecutor 基础教程

一、介绍

线程池是 Java 并发编程中核心的组件,本质是管理一组可复用线程的池化技术,目的是解决线程频繁创建 / 销毁的性能开销、控制并发线程数量、统一管理线程生命周期等问题。

补:什么是池化技术?

池化技术(Pooling Technology)是一种资源复用与管理的设计模式,核心思想是提前创建并维护一组可复用的资源对象池,当系统需要资源时直接从池中获取,用完后归还到池中而非销毁,从而避免频繁创建和销毁资源带来的性能开销。

简单来讲:池化 = 资源预创建 + 复用 + 统一管理

作用:
  1. 降低资源消耗:线程是重量级资源(占用栈内存、CPU 上下文),复用线程避免频繁创建 / 销毁的开销;
  2. 提高响应速度:任务到达时无需等待线程创建,直接复用空闲线程;
  3. 控制并发风险:避免无限制创建线程导致 CPU 满载、内存溢出(OOM);
  4. 便于统一管理:可监控线程状态、统计任务执行情况、设置超时 / 拒绝策略等。
二、原理

线程池的核心是ThreadPoolExecutor类(JDK 1.5+ 引入),其工作流程:

  1. 任务提交后,先判断核心线程池是否已满 → 未满则创建核心线程执行任务;
  2. 核心线程池满 → 判断任务队列是否已满 → 未满则将任务入队等待;
  3. 任务队列满 → 判断最大线程池是否已满 → 未满则创建非核心线程执行任务;
  4. 最大线程池满 → 触发拒绝策略处理无法执行的任务。
提交任务
核心线程数 < corePoolSize?
创建核心线程执行任务
阻塞队列是否已满?
任务进入阻塞队列等待
线程总数 < maximumPoolSize?
创建非核心线程执行任务
触发拒绝策略处理任务
任务执行完成
核心线程空闲时从队列取任务执行
非核心线程空闲时间 > keepAliveTime?
销毁非核心线程
非核心线程从队列取任务执行
线程池资源回收
AbortPolicy: 抛出RejectedExecutionException;
CallerRunsPolicy: 提交任务的线程自己执行;
DiscardPolicy: 直接丢弃任务;
DiscardOldestPolicy: 丢弃队列最旧任务再尝试提交
三、ThreadPoolExecutor参数

ThreadPoolExecutor的构造方法是理解线程池的关键,核心参数共 7 个:

publicThreadPoolExecutor(intcorePoolSize,// 核心线程数(常驻线程数,即使空闲也不会销毁)intmaximumPoolSize,// 最大线程数(线程池允许的最大线程数量)longkeepAliveTime,// 非核心线程空闲超时时间(超时后销毁)TimeUnitunit,// keepAliveTime 的时间单位(如秒、毫秒)BlockingQueue<Runnable>workQueue,// 任务等待队列(核心线程满后存放任务)ThreadFactorythreadFactory,// 线程创建工厂(自定义线程命名、优先级等)RejectedExecutionHandlerhandler// 拒绝策略(任务无法处理时的策略))
关键参数说明:
  1. **核心线程数(corePoolSize)**线程池长期维持的线程数量,即使线程空闲也不会销毁(除非设置allowCoreThreadTimeOut(true))。
  2. **最大线程数(maximumPoolSize)**线程池能创建的最大线程数,核心线程 + 非核心线程的总数不能超过此值。
  3. **任务队列(workQueue)**常用实现类:
    • ArrayBlockingQueue:有界数组队列(需指定容量,避免队列无限膨胀);
    • LinkedBlockingQueue:无界 / 有界链表队列(默认无界,易导致 OOM);
    • SynchronousQueue:同步队列(不存储任务,直接传递给线程,需配合大的 maximumPoolSize);
    • PriorityBlockingQueue:优先级队列(按任务优先级执行)。
  4. **拒绝策略(handler)**当线程池和任务队列都满时触发,JDK 提供 4 种默认策略:
    • AbortPolicy(默认):直接抛出RejectedExecutionException
    • CallerRunsPolicy:由提交任务的线程(如主线程)执行任务;
    • DiscardPolicy:静默丢弃任务,无任何提示;
    • DiscardOldestPolicy:丢弃队列中最旧的任务,尝试重新提交当前任务。
四、Java 内置线程池(Executors 工具类)

JDK 提供Executors快速创建常用线程池,但生产环境不推荐直接使用(易导致 OOM 或线程数失控),需手动自定义ThreadPoolExecutor

线程池类型核心参数适用场景风险点
FixedThreadPoolcorePoolSize=maximumPoolSize,队列无界执行长期稳定的任务任务堆积易 OOM
SingleThreadExecutor核心 / 最大线程数 = 1,队列无界串行执行任务任务堆积易 OOM
CachedThreadPoolcorePoolSize=0,maximumPoolSize=Integer.MAX_VALUE,队列同步队列执行短期异步任务线程数失控易 OOM
ScheduledThreadPool核心线程数固定,最大线程数 = Integer.MAX_VALUE执行延迟 / 周期性任务任务过多易 OOM
五、线程池使用示例(推荐自定义)
importjava.util.concurrent.*;publicclassThreadPoolDemo{publicstaticvoidmain(String[]args){// 1. 定义核心参数intcorePoolSize=Runtime.getRuntime().availableProcessors();// CPU核心数intmaximumPoolSize=corePoolSize*2;longkeepAliveTime=60L;TimeUnitunit=TimeUnit.SECONDS;// 有界队列(避免无界队列OOM)BlockingQueue<Runnable>workQueue=newArrayBlockingQueue<>(100);// 自定义线程工厂(便于排查问题)ThreadFactorythreadFactory=newThreadFactory(){privateintcount=0;@OverridepublicThreadnewThread(Runnabler){Threadthread=newThread(r);thread.setName("demo-thread-"+count++);thread.setDaemon(false);// 非守护线程thread.setPriority(Thread.NORM_PRIORITY);returnthread;}};// 自定义拒绝策略(日志+抛异常)RejectedExecutionHandlerhandler=(r,executor)->{System.err.println("任务 "+r+" 被拒绝,线程池状态:"+"核心线程数="+executor.getCorePoolSize()+",活跃线程数="+executor.getActiveCount()+",队列大小="+executor.getQueue().size());thrownewRejectedExecutionException("任务 "+r+" 执行失败");};// 2. 创建线程池ThreadPoolExecutorexecutor=newThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler);// 3. 提交任务(推荐使用submit,可获取返回值/异常)for(inti=0;i<10;i++){intfinalI=i;Future<Integer>future=executor.submit(()->{System.out.println(Thread.currentThread().getName()+" 执行任务:"+finalI);returnfinalI*2;});// 获取任务结果(需处理异常)try{System.out.println("任务"+finalI+"结果:"+future.get());}catch(InterruptedException|ExecutionExceptione){e.printStackTrace();}}// 4. 关闭线程池(必须手动关闭,否则JVM不会退出)executor.shutdown();// 平缓关闭:等待已提交任务执行完毕// executor.shutdownNow(); // 强制关闭:中断所有线程,返回未执行的任务try{// 等待线程池关闭,超时则强制退出if(!executor.awaitTermination(5,TimeUnit.MINUTES)){executor.shutdownNow();}}catch(InterruptedExceptione){executor.shutdownNow();}}}
六、线程池核心状态

线程池通过ctl原子变量维护状态,核心状态包括:

  • RUNNING:接收新任务,处理队列任务;
  • SHUTDOWN:不接收新任务,处理队列任务;
  • STOP:不接收新任务,不处理队列任务,中断正在执行的任务;
  • TIDYING:所有任务执行完毕,线程数为 0,准备执行terminated()钩子;
  • TERMINATEDterminated()执行完毕。
七、注意
  1. 避免使用 Executors 默认实现:手动自定义ThreadPoolExecutor,指定有界队列和合理的核心 / 最大线程数;
  2. 核心线程数设置:
    • CPU 密集型任务(如计算):核心线程数 = CPU 核心数 + 1(减少线程切换);
    • IO 密集型任务(如数据库 / 网络请求):核心线程数 = CPU 核心数 * 2(利用空闲时间);
  3. 监控线程池状态:通过getActiveCount()getQueue().size()getCompletedTaskCount()等方法监控;
  4. 优雅关闭线程池:使用shutdown()+awaitTermination(),避免强制关闭导致任务丢失;
  5. 捕获任务异常:使用submit()提交任务,通过Future.get()捕获异常(execute()无法捕获任务内异常);
  6. 避免任务长时间阻塞:如数据库查询设置超时,防止线程长期占用导致线程池耗尽。
八、总结

Java 线程池的核心是ThreadPoolExecutor,通过核心线程、最大线程、任务队列、拒绝策略的组合,实现线程的复用和并发控制。生产环境中需根据业务场景自定义参数,避免默认实现的坑,同时做好监控和优雅关闭,确保线程池稳定运行。

附表:

JDK 版本发布时间线程池核心变化关键说明
JDK 1.52004 年首次引入线程池核心 API✅ 新增java.util.concurrent包✅ 核心类:ThreadPoolExecutorScheduledThreadPoolExecutor✅ 工具类:Executors(提供固定 / 缓存 / 单线程池等工厂方法)✅ 核心接口:ExecutorExecutorServiceScheduledExecutorService线程池的 “奠基版本”,解决了手动创建线程的性能问题,定义了线程池的核心模型(核心线程、最大线程、队列、拒绝策略);Executors提供的默认实现(如newCachedThreadPool)成为主流用法,但后续被指出存在配置风险。
JDK 1.62006 年性能优化 + 细节补充✅ 优化ThreadPoolExecutor的线程回收逻辑✅ 新增ThreadPoolExecutor.afterExecute()方法(支持任务执行后回调)✅ 完善ScheduledThreadPoolExecutor的定时任务精度无核心 API 变更,主要是性能调优和扩展性增强;回调方法的补充让线程池的监控 / 日志能力更灵活。
JDK 1.72011 年无核心变更线程池相关 API 无新增 / 修改,仅跟随 JDK 整体的并发包优化(如 Fork/Join 框架引入,但与线程池无关)。
JDK 1.82014 年Lambda 适配 + 小优化✅ 支持 Lambda 表达式简化任务提交(executor.submit(() -> { ... }))✅ 优化ThreadPoolExecutor的队列调度逻辑✅ 修复ScheduledThreadPoolExecutor的任务取消 bug核心功能无变化,主要是适配 Lambda 提升易用性;修复了定时任务中已取消任务仍可能执行的问题。
JDK 92017 年模块化 + 废弃部分 API✅java.util.concurrent归入java.base模块✅ 废弃ExecutorsnewWorkStealingPool(int)重载方法(仅保留无参版)✅ 新增ExecutorService.shutdownNow()的返回值优化(更精准返回未执行任务)模块化调整不影响使用;废弃的newWorkStealingPool(int)因参数设计不合理被移除,无参版(基于 CPU 核心数)保留。
JDK 102018 年无核心变更仅小范围 bug 修复,无线程池相关 API 调整。
JDK 11(LTS)2018 年性能优化 + 安全增强✅ 优化ThreadPoolExecutor的锁竞争(减少核心线程创建时的锁开销)✅ 修复ScheduledThreadPoolExecutor的内存泄漏问题✅ 新增ExecutorServicesubmit方法异常处理优化LTS 版本,核心稳定,主要是生产环境级别的 bug 修复和性能调优;解决了长期运行的定时线程池可能导致的内存泄漏问题。
JDK 12 - 192019-2022 年无核心 API 变更✅ 小范围 bug 修复(如线程池拒绝策略触发时机)✅ JDK 19 新增虚拟线程预览特性(不影响传统线程池)传统线程池 API 进入 “维护期”,无新功能;虚拟线程(Project Loom)开始预览,但属于全新的并发模型,与传统线程池并行存在。
JDK 202023 年虚拟线程转正(预览→孵化)✅Executors.newVirtualThreadPerTaskExecutor()(创建虚拟线程池)✅ 传统线程池 API 无变更虚拟线程池成为正式孵化特性,但传统线程池仍为核心;虚拟线程池不替代传统线程池,适用于 IO 密集型场景。
JDK 21(LTS)2023 年虚拟线程正式 GA✅ 虚拟线程(VirtualThread)成为正式特性✅ 新增Executors.newVirtualThreadPerTaskExecutor()(稳定 API)✅ 传统线程池(ThreadPoolExecutor)完全兼容,无废弃 / 修改里程碑版本:虚拟线程池正式可用,传统线程池仍为 “CPU 密集型任务” 的首选;核心变化:线程池分为 “平台线程池”(传统)和 “虚拟线程池”(新),按需选择。

注:

虚拟线程(VirtualThread) 是 JDK 21 正式纳入标准的轻量级用户态线程(属于 Project Loom 核心特性),核心是通过M:N 映射模型(M 个虚拟线程映射到 N 个操作系统内核线程)实现高效的并发处理,

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询