ExecutorService 是 Java 并发包中可管控、可复用的线程池抽象,解决手动创建线程导致的初始化/销毁开销大、线程数失控、缺乏生命周期管理三大问题,基于 ThreadPoolExecutor 实现,需显式调用 shutdown 等方法确保资源释放。

ExecutorService 是 Java 并发包(java.util.concurrent)中用于管理异步任务执行的核心接口,本质是一个**可管控、可复用的线程池抽象**。它不直接创建线程,而是把“提交任务”和“调度执行”解耦——你只管交任务,它负责用已有或按需创建的线程去跑,避免频繁 new Thread() 带来的开销和资源失控。
ExecutorService 解决什么问题
手动创建线程有三大痛点:
- 每次
new Thread().start()都要花时间初始化(T1)和销毁(T3),而真正干活的时间(T2)可能很短;当请求量大时,T1+T3 远超 T2,性能被严重拖累 - 线程数量不受控:5 万请求就起 5 万个线程,极易耗尽内存、触发 OOM 或引发上下文切换风暴
- 缺乏统一生命周期管理:无法优雅等待任务结束、无法批量取消、无法获取返回值、难以监控状态
ExecutorService 正是为这些场景设计:复用线程、限制并发、统一封装调度与关闭逻辑。
底层是怎么工作的
所有标准线程池(如 newFixedThreadPool、newCachedThreadPool)最终都基于 ThreadPoolExecutor 构建。它的运行依赖五个关键要素:
立即学习“Java免费学习笔记(深入)”;
- corePoolSize:核心线程数,线程池启动后常驻的最小线程数,空闲也不会回收
- maximumPoolSize:最大线程数,当任务积压且队列已满时,允许临时扩容至此数
- keepAliveTime + unit:非核心线程空闲超时后被回收的时间阈值
-
workQueue:阻塞队列,缓存待执行的 Runnable/Callable 任务(如
LinkedBlockingQueue、SynchronousQueue) - RejectedExecutionHandler:当队列满 + 线程达上限时,对新任务的兜底策略(如丢弃、抛异常、由调用线程自己执行等)
常用创建方式与适用场景
通过 Executors 工厂类快速创建,但要注意其封装隐藏了风险(如 newFixedThreadPool 默认用无界队列,可能OOM):
-
newFixedThreadPool(n):固定 n 个线程,适合负载稳定、强调可控并发的场景(如 Web 请求处理) -
newSingleThreadExecutor():单线程串行执行,保证任务顺序,适合日志写入、配置更新等需强序操作 -
newCachedThreadPool():核心线程数为 0,最大无限,空闲 60 秒回收;适合大量短时异步任务(如 RPC 调用回调) -
newScheduledThreadPool(n):支持schedule()和scheduleAtFixedRate(),替代老旧的Timer
生产环境更推荐直接使用 ThreadPoolExecutor 构造器,显式指定队列容量和拒绝策略,避免隐式风险。
怎么提交和管理任务
两类提交方式:
-
execute(Runnable):只执行,无返回值,适合“发完即忘”的后台任务 -
submit(Runnable)或submit(Callable:返回) Future,可查询状态、阻塞获取结果、主动取消
生命周期控制必须做:
-
shutdown():停止接收新任务,等已有任务执行完再关闭(推荐) -
shutdownNow():尝试中断所有正在运行的线程,返回未开始的任务列表(慎用) -
awaitTermination(timeout, unit):配合 shutdown 使用,等待最多指定时间,判断是否真正关闭成功
不调用 shutdown,线程池会一直持有线程不释放,导致应用无法正常退出。










