源码:java.util.concurrent.ExecutorService 源码解析

1. TODO


2. 脑图

  1. Xmind

  2. Edraw

  3. Hexo 地址
    👉 http://blog.wangjia.ink/2025/09/03/源码:java.util.concurrent.ExecutorService源码解析/


3. 基础部分

ExecutorService 概述

ExecutorService 是一个接口,继承了 java.util.concurrent.Executor

ExecutorServiceExecutor 的基础上,为我们提供了以下方法:

  1. 关闭线程池(非阻塞)
  2. 等待线程池关闭(限时阻塞)
  3. 查看线程池是否关闭(非阻塞)
  4. 查看线程池是否被执行过 ExecutorService#shutdownExecutorService#shutdownNow(非阻塞)
  5. 提交一个 Callable 任务(非阻塞)
  6. 提交一个 Runnable 任务(非阻塞)
  7. 提交一批 Callable 任务(阻塞、限时阻塞)

[!NOTE] 注意事项

  1. 详见源码:Executor
    1. obsidian 内部链接:
      1. 源码:java.util.concurrent.Executor源码解析
    2. Hexo 链接:
      1. http://blog.wangjia.ink/2025/08/31/源码:java.util.concurrent.Executor源码解析/

2. 源码部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
public interface ExecutorService extends Executor {

// 用于非阻塞有序关闭线程池
//
//
// 已提交的任务会继续执行,但线程池不会再接收新的任务
void shutdown();

// 用于非阻塞强制关闭线程池
//
// 正在运行的任务会被停止,并且返回还没开始执行的 Runnable 任务列表,线程池不会再接收新的任务
List<Runnable> shutdownNow();

// 用于非阻塞查看线程池是否被执行过 ExecutorService#shutdown 或 ExecutorService#shutdownNow
boolean isShutdown();

// 用于非阻塞查看线程池是否关闭
boolean isTerminated();

// 用于限时阻塞等待线程池关闭
//
// 限时阻塞被允许的最长时间为:timeout unit
// 1. 如果超时,返回 false
//
// 如果线程池未关闭,本地线程进入阻塞状态,Thread 实例进入 TIMED_WAITING 状态,并被投递到 ExecutorService 接口的具体实现类维护的某数据结构,等待被唤醒(LockSupport.unpark)、被中断(Thread#interrupt)、阻塞超时
//
// 本地线程进入阻塞状态,Thread 实例进入 TIMED_WAITING 状态后,能响应中断。线程被唤醒,重新获得 CPU 时间片后,会抛出 InterruptedException 异常,并清除 Thread 实例的中断状态(异常退出或正常退出(发生异常),要看我们是否对该异常进行捕获并处理)
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;

// 用于非阻塞提交一个 Callable 任务
<T> Future<T> submit(Callable<T> task);

// 用于非阻塞提交一个 Runnable 任务,并手动指定一个任务结果
//
// 因为 Runnable 任务没有返回结果,如果你需要一个返回结果的话,可以手动指定
<T> Future<T> submit(Runnable task, T result);

// 用于非阻塞提交一个 Runnable 任务
//
// 该方法与 Executor#execute 的区别在于:
// 1. Executor#execute 只管提交,不问结果。它没有返回值,你无法知道任务是否执行成功,也无法知道任务的执行结果
// 2. 而 ExecutorService.submit 是提交任务,返回该任务对应的 Future 接口的具体实现类实例。我们可以根据返回的 Future 接口的具体实现类实例对该任务进行一系列操作
// 3. 需要注意的是,如果你提交的是 Runnable 任务,即便你使用 Future 接口的具体实现类实例获取该任务的结果,也只会是 null 或我们手动指定的任务结果。我们通常使用 Future 接口的具体实现类实例获取 Callable 任务的结果
Future<?> submit(Runnable task);

// 用于阻塞提交一批 Callable 任务,并等待所有任务执行完毕(正常退出、异常退出、取消任务)后,再返回这些任务对应的 Future接口的具体实现类实例列表
//
// 在等待任务执行完毕的过程中,本地线程进入阻塞状态,Thread 实例进入 WAITING 状态,等待被唤醒(LockSupport.unpark)、被中断(Thread#interrupt)
//
// 本地线程进入阻塞状态,Thread 实例进入 WAITING 状态后,能响应中断。线程被唤醒,重新获得 CPU 时间片后,会抛出 InterruptedException 异常,并清除 Thread 实例的中断状态(异常退出或正常退出(发生异常),要看我们是否对该异常进行捕获并处理)
//
// 需要注意的是:
// 1. 它并不像传统模式那样将任务统一投递到某个固定的数据结构中,而是循环调用每个 Future 接口的具体实现类实例的 Future#get
// 2. 因此 Thread 实例可能被投递到多个 Future 接口的具体实现类实例维护的某数据结构
// 3. 除此之外,这还意味着阻塞状态也是一段一段的,而不是从头到尾一直阻塞
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;

// 用于限时阻塞提交一批 Callable 任务,并等待所有任务执行完毕(正常退出、异常退出、取消任务)后,再返回这些任务对应的 Future 接口的具体实现类实例列表
//
// 限时阻塞被允许的最长时间为:timeout unit
// 1. 如果超时,会撤销尚未执行的任务
//
// 在等待任务执行完毕的过程中,本地线程进入阻塞状态,Thread 实例进入 TIMED_WAITING 状态,等待被唤醒(LockSupport.unpark)、被中断(Thread#interrupt)、阻塞超时
//
// 本地线程进入阻塞状态,Thread 实例进入 TIMED_WAITING 状态后,能响应中断。线程被唤醒,重新获得 CPU 时间片后,会抛出 InterruptedException 异常,并清除 Thread 实例的中断状态(异常退出或正常退出(发生异常),要看我们是否对该异常进行捕获并处理)
//
// 需要注意的是:
// 1. 它并不像传统模式那样将任务统一投递到某个固定的数据结构中,而是循环调用每个 Future 接口的具体实现类实例的 Future#get
// 2. 因此 Thread 实例可能被投递到多个 Future 接口的具体实现类实例维护的某数据结构
// 3. 除此之外,这还意味着阻塞状态也是一段一段的,而不是从头到尾一直阻塞
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;

// 用于阻塞提交一批 Callable 任务,等待 “任意” 且 “第一个” 任务执行成功(正常退出),立即返回该任务的结果(并不是该任务对应的 Future 接口的具体实现类实例),并撤销尚未执行的任务和停止正在执行的任务
//
// 在等待 “任意” 且 “第一个” 任务执行程序的过程中,本地线程进入 WAITING 状态,并被投递到 ExecutorCompletionService 维护的某数据结构,等待被唤醒(LockSupport.unpark)、被中断(Thread#interrupt)
//
// 本地线程进入阻塞状态,Thread 实例进入 WAITING 状态后,能响应中断。线程被唤醒,重新获得 CPU 时间片后,会抛出 InterruptedException 异常,并清除 Thread 实例的中断状态(异常退出或正常退出(发生异常),要看我们是否对该异常进行捕获并处理)
//
// 如果所有任务都执行失败,会抛出 ExecutionException 异常
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;

// 用于限时阻塞提交一批 Callable 任务,等待 “任意” 且 “第一个” 任务执行成功(正常退出),立即返回该任务的结果(并不是该任务对应的 Future 实例),并 “尽力” 取消未执行的任务和停止正在执行的任务
//
// 限时阻塞被允许的最长时间为:timeout unit
// 1. 如果超时,会抛出 TimeoutException 异常
//
// 在等待 “任意” 且 “第一个” 任务执行程序的过程中,本地线程进入 TIMED_WAITING 状态,并被投递到 ExecutorCompletionService 维护的某数据结构,等待被唤醒(LockSupport.unpark)、被中断(Thread#interrupt)、阻塞超时
//
// 本地线程进入阻塞状态,Thread 实例进入 TIMED_WAITING 状态后,能响应中断。线程被唤醒,重新获得 CPU 时间片后,会抛出 InterruptedException 异常,并清除 Thread 实例的中断状态(异常退出或正常退出(发生异常),要看我们是否对该异常进行捕获并处理)
//
// 如果所有任务都执行失败,会抛出 ExecutionException 异常
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}

[!NOTE] 注意事项

  1. 取消任务和停止任务还是有所区别的:取消任务是指取消那些尚未执行的任务。而停止任务则是任务正在执行时,你通过中断去让它停下来。如果任务能够响应中断,那就算是成功停止。但问题在于,如果任务没有响应中断,那么即使你发出了中断请求,它仍然会继续执行。所以 “停止任务” 并不一定能让它 “停止下来”


源码:java.util.concurrent.ExecutorService 源码解析
https://wangjia5289.github.io/2025/09/03/源码:java.util.concurrent.ExecutorService源码解析/
Author
咸阳猴🐒
Posted on
September 3, 2025
Licensed under