目录
四、(重点)ThreadPoolExecutor的execute方法
五、 ThreadPoolExecutor的addworker方法
六、ThreadPoolExecutor的Worker工作线程
七、ThreadPoolExecutor的runWorker方法
八、ThreadPoolExecutor的getTask方法
一、ThreadPoolExecutor的核心属性
最核心的属性就是crl,基于ctl拿到的线程池的状态以及工作线程个数。
基于上面的源码,对其变量一个个的分析
1、ctl
- private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
- ctl其实就是一个int类型的数值,内部是基于AtomicInteger(CAS)包装了一层,运行计算时是原子性的。
- ctl表示着线程池中的2个核心状态 ( 线程池的状态 & 工作线程个数)
- 线程池的状态: ctl的高3位,表示线程池的状态。
- 工作线程个数:ctl的低29位,表示工作线程个数。
2、COUNT_BITS
- private static final int COUNT_BITS = Integer.SIZE - 3;
- Integer.SIZE :获取Integer的bit位个数 (32位)
- 所以这里就是声明了一个产量 COUNT_BITS = 29
3、CAPACITY
- private static final int CAPACITY = (1 << COUNT_BITS) - 1;
- (1 << COUNT_BITS) - 1 做了什么
- 00000000 00000000 00000000 00000001 -- 数值为 1 的int 值
- 00100000 00000000 00000000 00000000 -- 左移 COUNT_BITS 位
- 00011111 11111111 11111111 11111111 -- 左移后做“减1”操作
- 所以CAPACITY 就是当前工作线程能记录的工作线程最大个数
4、线程池的状态
当前5个状态中,只有RUNNING 状态代表线程池没有问题,可以正常接收任务处理
1、RUNNING
- -1 << COUNT_BITS = 111
- 111: 代表RUNNING 状态,RUNNING可以处理任务,并且处理阻塞队列中的任务。
2、SHUTDOWN
- 0 << COUNT_BITS = 000
- 000:代表SHUTDOWN状态,不会接收新任务,正在处理的任务正常进行,阻塞队列的任务也会处理完
3、STOP
- 1 << COUNT_BITS = 001
- 001:代表STOP 状态,不会接收新任务,正在处理任务的线程也会被中断,阻塞队列中待执行的任务也一个都不管了。
4、TIDYING
- 2 << COUNT_BITS = 010
- 010:代表TIDYING状态,这个状态就是SHUTDOWN或者STOP状态转换过来的,代表当前线程池马上就要关闭了,就是一个过度状态
5、TERMINATED
- 3 << COUNT_BITS = 011
- 011:代表TERMINATED状态,这个状态就是TIDYING转换过来的。转换过来只需要执行一个terminated方法。
5、runStateOf方法
- 需要传参 ctl
- 基于&运算符的特点,保证只会拿到ctl高3位的值
6、workerCountOf方法
- 需要传参ctl
- 基于&运算符的特点,保证只会拿到ctl低29位的值
二、线程池状态的特点以及转换的方式
三、ThreadPoolExecutor的有参构造方法
// 有参构造。无论调用哪个有参构造,最终都会执行当前的有参构造
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
// 健壮性校验
// 核心线程个数是允许为0个的。
// 最大线程数必须大于0,最大线程数要大于等于核心线程数
// 非核心线程的最大空闲时间,可以等于0
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
// 不满足要求就抛出参数异常
throw new IllegalArgumentException();
// 阻塞队列,线程工厂,拒绝策略都不允许为null,为null就扔空指针异常
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
// 不要关注当前内容,系统资源访问决策,和线程池核心业务关系不大。
this.acc = System.getSecurityManager() == null ? null : AccessController.getContext();
// 各种赋值,JUC包下,几乎所有涉及到线程挂起的操作,单位都用纳秒。
// 有参构造的值,都赋值给成员变量。
// Doug Lea的习惯就是将成员变量作为局部变量单独操作。
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
四、(重点)ThreadPoolExecutor的execute方法
当核心线程满了,任务会扔到阻塞队列,当阻塞队列满了,如果再来任务,才会尝试创建非核心线程
如果当前正在运行的核心线程数小于corePoolSize,线程池会优先创建新的核心线程来执行任务,而不是直接将任务放入队列或创建非核心线程。
// 提交任务到线程池的核心方法
// command就是提交过来的任务
public void execute(Runnable command) {
// 提交的任务不能为null
if (command == null)
throw new NullPointerException();
// 获取核心属性ctl,用于后面的判断
int c = ctl.get();
// 如果工作线程个数(workerCountOf(c)),小于核心线程数(corePoolSize),这个核心线程数就是在创建ThreadPoolExecutor时指定的。
// 满足要求,添加核心工作线程
if (workerCountOf(c) < corePoolSize) {
// addWorker(任务,是核心线程吗)
// addWorker会返回boolean,ture代表添加工作线程成功,fasle代表失败
// addWorker中会基于线程池状态,以及工作线程个数做判断,查看能否添加工作线程
if (addWorker(command, true)) {
// 工作线程构建出来了,任务也交给command去处理了。
return;
}
// 说明线程池状态或者是工作线程个数发生了变化,导致添加失败,重新获取一次ctl
c = ctl.get();
}
// 添加核心工作线程失败(包括:1、执行添加任务失败;2、当前工作线程>= 核心线程数)
// 看完这个源码可以知道,当核心工作线程创建满之前是不会去创建非核心工作线程的。
// 判断线程池状态是否是RUNNING,如果是,正常基于阻塞队列的offer方法,将任务添加到阻塞队列
if (isRunning(c) && workQueue.offer(command)) {
// 如果任务添加到阻塞队列成功,走if内部
// 如果任务在扔到阻塞队列之前,线程池状态突然改变了。
// 重新获取ctl
int recheck = ctl.get();
// 如果线程池的状态不是RUNNING,将任务从阻塞队列移除,
if (!isRunning(recheck) && remove(command)) {
// 并且直接拒绝策略
reject(command);
}
// 在这,说明阻塞队列有我刚刚放进去的任务
// 查看一下工作线程数是不是0个
// 如果工作线程为0个,需要添加一个非核心工作线程去处理阻塞队列中的任务
// 发生这种情况有两种:
// 1. 构建线程池时,核心线程数是0个。
// 2. 即便有核心线程,可以设置核心线程也允许超时,设置allowCoreThreadTimeOut为true,代表核心线程也可以超时
else if (workerCountOf(recheck) == 0) {
// 为了避免阻塞队列中的任务饥饿,添加一个非核心工作线程去处理
addWorker(null, false);
}
}
// 任务添加到阻塞队列失败(包含:1、线程池的状态有问题,即不为RUNNING状态;2、执行添加任务失败)
// 构建一个非核心工作线程
// 如果添加非核心工作线程成功,就万事大吉
else if (!addWorker(command, false)) {
// 添加失败,执行决绝策略
reject(command);
}
}
看一下execute方法完整执行流程图
五、 ThreadPoolExecutor的addworker方法
这个方法就是在executor 中有调用到的方法
addWorker方法要分两部分分析:
1、校验线程池的状态以及工作线程个数
2、添加工作线程并且启动工作线程
第一部分:校验
分两层死循环:
1、第一层是判断线程池的状态
2、第二层是判断线程池的线程数量
// 添加工作线程之校验源码
private boolean addWorker(Runnable firstTask, boolean core) {
// 外层for循环在校验线程池的状态
// 内层for循环是在校验工作线程的个数
// retry是给外层for循环添加一个标记,是为了方便在内层for循坏跳出外层for循环
retry:
for (;;) {
// 获取ctl
int c = ctl.get();
// 拿到ctl的高3位的值
int rs = runStateOf(c);
//====================线程池状态判断====================
// 如果线程池状态是SHUTDOWN,并且此时阻塞队列有任务,工作线程个数为0,添加一个工作线程去处理阻塞队列的任务
// 判断线程池的状态是否大于等于SHUTDOWN,如果满足,说明线程池不是RUNNING
if (rs >= SHUTDOWN &&
// 如果这三个条件都满足,就代表是要添加非核心工作线程去处理阻塞队列任务
// 如果三个条件有一个没满足,返回false,配合!,就代表不需要添加
!(rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()))
// 不需要添加工作线程
return false;
for (;;) {
// ====================工作线程个数判断====================
// 基于ctl拿到低29位的值,代表当前工作线程个数
int wc = workerCountOf(c);
// 如果工作线程个数大于最大值了,不可以添加了,返回false
if (wc >= CAPACITY ||
// 基于core来判断添加的是否是核心工作线程
// 如果是核心:基于corePoolSize去判断
// 如果是非核心:基于maximumPoolSize去判断
wc >= (core ? corePoolSize : maximumPoolSize))
// 代表不能添加,工作线程个数不满足要求
return false;
// 针对ctl进行 + 1,采用CAS的方式
if (compareAndIncrementWorkerCount(c))
// CAS成功后,直接退出外层循环,代表可以执行添加工作线程操作了。
break retry;
// 重新获取一次ctl的值
c = ctl.get();
// 判断重新获取到的ctl中,表示的线程池状态跟之前的是否有区别
// 如果状态不一样,说明有变化,重新的去判断线程池状态
if (runStateOf(c) != rs)
// 跳出一次外层for循环
continue retry;
}
}
// 省略添加工作线程以及启动的过程
}
第二部分:执行
private boolean addWorker(Runnable firstTask, boolean core) {
// 省略校验部分的代码
// 添加工作线程以及启动工作线程~~~
// 声明了三个变量
// 工作线程启动了没,默认false
boolean workerStarted = false;
// 工作线程添加了没,默认false
boolean workerAdded = false;
// 工作线程,默认为null
Worker w = null;
try {
// 构建工作线程,并且将任务传递进去
w = new Worker(firstTask);
// 获取了Worker中的Thread对象
final Thread t = w.thread;
// 判断Thread是否不为null,在new Worker时,内部会通过给予的ThreadFactory去构建Thread交给Worker
// 一般如果为null,代表ThreadFactory有问题。
if (t != null) {
// 加锁,保证使用workers成员变量以及对largestPoolSize赋值时,保证线程安全
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 再次获取线程池状态。
int rs = runStateOf(ctl.get());
// 再次判断
// 如果满足 rs < SHUTDOWN 说明线程池是RUNNING,状态正常,执行if代码块
// 如果线程池状态为SHUTDOWN,并且firstTask为null,添加非核心工作处理阻塞队列任务
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 到这,可以添加工作线程。
// 校验ThreadFactory构建线程后,不能自己启动线程,如果启动了,抛出异常
if (t.isAlive())
throw new IllegalThreadStateException();
// private final HashSet<Worker> workers = new HashSet<Worker>();
// 将new好的Worker添加到HashSet中。
workers.add(w);
// 获取了HashSet的size,拿到工作线程个数
int s = workers.size();
// largestPoolSize在记录最大线程个数的记录
// 如果当前工作线程个数,大于最大线程个数的记录,就赋值
if (s > largestPoolSize)
largestPoolSize = s;
// 添加工作线程成功
workerAdded = true;
}
} finally {
mainLock.unlock();
}
// 如果工作线程添加成功,
if (workerAdded) {
// 直接启动Worker中的线程
t.start();
// 启动工作线程成功
workerStarted = true;
}
}
} finally {
// 做补偿的操作,如果工作线程启动失败,将这个添加失败的工作线程处理掉
if (!workerStarted)
addWorkerFailed(w);
}
// 返回工作线程是否启动成功
return workerStarted;
}
// 工作线程启动失败,需要不的步长操作
private void addWorkerFailed(Worker w) {
// 因为操作了workers,需要加锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 如果w不为null,之前Worker已经new出来了。
if (w != null)
// 从HashSet中移除
workers.remove(w);
// 同时对ctl进行 - 1,代表去掉了一个工作线程个数
decrementWorkerCount();
// 因为工作线程启动失败,判断一下状态的问题,是不是可以走TIDYING状态最终到TERMINATED状态了。
tryTerminate();
} finally {
// 释放锁
mainLock.unlock();
}
}
六、ThreadPoolExecutor的Worker工作线程
Worker对象主要包含了两个内容
-
工作线程要执行任务
-
工作线程可能会被中断--控制中断
// Worker继承了AQS,目的就是为了控制工作线程的中断。 // Worker实现了Runnable,内部的Thread对象,在执行start时,必然要执行Worker中断额一些操作 private final class Worker extends AbstractQueuedSynchronizer implements Runnable{ // ===Worker管理任务=== // 线程工厂构建的线程 final Thread thread; // 当前Worker要执行的任务 Runnable firstTask; // 记录当前工作线程处理了多少个任务。 volatile long completedTasks; // 有参构造 Worker(Runnable firstTask) { // 将State设置为-1,代表当前不允许中断线程 setState(-1); // 任务赋值 this.firstTask = firstTask; // 基于线程工作构建Thread,并且传入的Runnable是Worker this.thread = getThreadFactory().newThread(this); } // 当thread执行start方法时,调用的是Worker的run方法, public void run() { // 任务执行时,执行的是runWorker方法 runWorker(this); } // ===Worker管理中断=== // 当前方法是中断工作线程时,执行的方法 void interruptIfStarted() { Thread t; // 只有Worker中的state >= 0的时候,可以中断工作线程 if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) { try { // 如果状态正常,并且线程未中断,这边就中断线程 t.interrupt(); } catch (SecurityException ignore) { } } } protected boolean isHeldExclusively() { return getState() != 0; } protected boolean tryAcquire(int unused) { if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } protected boolean tryRelease(int unused) { setExclusiveOwnerThread(null); setState(0); return true; } public void lock() { acquire(1); } public boolean tryLock() { return tryAcquire(1); } public void unlock() { release(1); } public boolean isLocked() { return isHeldExclusively(); } }
七、ThreadPoolExecutor的runWorker方法
runWorker就是让工作线程拿到任务去执行即可。
并且在内部也处理了在工作线程正常结束和异常结束时的处理方案
// 工作线程启动后执行的任务。 final void runWorker(Worker w) { // 拿到当前线程 Thread wt = Thread.currentThread(); // 从worker对象中拿到任务 Runnable task = w.firstTask; // 将Worker中的firstTask置位空 w.firstTask = null; // 将Worker中的state置位0,代表当前线程可以中断的 w.unlock(); // 判断工作线程是否是异常结束,默认就是异常结束 boolean completedAbruptly = true; try { // 获取任务 // 直接拿到第一个任务去执行 // 如果第一个任务为null,去阻塞队列中获取任务 while (task != null || (task = getTask()) != null) { // 执行了Worker的lock方法,当前在lock时,shutdown操作不能中断当前线程,因为当前线程正在处理任务 w.lock(); // 比较ctl >= STOP,如果满足找个状态,说明线程池已经到了STOP状态甚至已经要凉凉了 // 线程池到STOP状态,并且当前线程还没有中断,确保线程是中断的,进到if内部执行中断方法 // if(runStateAtLeast(ctl.get(), STOP) && !wt.isInterrupted()) {中断线程} // 如果线程池状态不是STOP,确保线程不是中断的。 // 如果发现线程中断标记位是true了,再次查看线程池状态是大于STOP了,再次中断线程 // 这里其实就是做了一个事情,如果线程池状态 >= STOP,确保线程中断了。 if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP)) ) && !wt.isInterrupted()){ wt.interrupt(); } try { // 勾子函数在线程池中没有做任何的实现,如果需要在线程池执行任务前后做一些额外的处理,可以重写勾子函数 // 前置勾子函数 beforeExecute(wt, task); Throwable thrown = null; try { // 执行任务。 task.run(); } catch (RuntimeException x) { thrown = x; throw x; } catch (Error x) { thrown = x; throw x; } catch (Throwable x) { thrown = x; throw new Error(x); } finally { // 前后置勾子函数 afterExecute(task, thrown); } } finally { // 任务执行完,丢掉任务 task = null; // 当前工作线程处理的任务数+1 w.completedTasks++; // 执行unlock方法,此时shutdown方法才可以中断当前线程 w.unlock(); } } // 如果while循环结束,正常走到这,说明是正常结束 // 正常结束的话,在getTask中就会做一个额外的处理,将ctl - 1,代表工作线程减少一个。 completedAbruptly = false; } finally { // 考虑干掉工作线程 processWorkerExit(w, completedAbruptly); } } // 工作线程结束前,要执行当前方法 private void processWorkerExit(Worker w, boolean completedAbruptly) { // 如果是异常结束 if (completedAbruptly) // 将ctl - 1,扣掉一个工作线程 decrementWorkerCount(); // 操作Worker,为了线程安全,加锁 final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { // 当前工作线程处理的任务个数累加到线程池处理任务的个数属性中 completedTaskCount += w.completedTasks; // 将工作线程从hashSet中移除 workers.remove(w); } finally { // 释放锁 mainLock.unlock(); } // 只要工作线程凉了,查看是不是线程池状态改变了。 tryTerminate(); // 获取ctl int c = ctl.get(); // 判断线程池状态,当前线程池要么是RUNNING,要么是SHUTDOWN if (runStateLessThan(c, STOP)) { // 如果正常结束工作线程 if (!completedAbruptly) { // 如果核心线程允许超时,min = 0,否则就是核心线程个数 int min = allowCoreThreadTimeOut ? 0 : corePoolSize; // 如果min == 0,可能会出现没有工作线程,并且阻塞队列有任务没有线程处理 if (min == 0 && ! workQueue.isEmpty()) // 至少要有一个工作线程处理阻塞队列任务 min = 1; // 如果工作线程个数 大于等于1,不怕没线程处理,正常return if (workerCountOf(c) >= min) return; } // 异常结束,为了避免出现问题,添加一个空任务的非核心线程来填补上刚刚异常结束的工作线程 addWorker(null, false); } }
八、ThreadPoolExecutor的getTask方法
工作线程在去阻塞队列获取任务前,要先查看线程池状态
如果状态没问题,去阻塞队列take或者是poll任务
第二个循环时,不但要判断线程池状态,还要判断当前工作线程是否可以被干掉
// 当前方法就在阻塞队列中获取任务 // 前面半部分是判断当前工作线程是否可以返回null,结束。 // 后半部分就是从阻塞队列中拿任务 private Runnable getTask() { // timeOut默认值是false。 boolean timedOut = false; // 死循环 for (;;) { // 拿到ctl int c = ctl.get(); // 拿到线程池的状态 int rs = runStateOf(c); // 如果线程池状态是STOP,没有必要处理阻塞队列任务,直接返回null // 如果线程池状态是SHUTDOWN,并且阻塞队列是空的,直接返回null if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { // 如果可以返回null,先扣减工作线程个数 decrementWorkerCount(); // 返回null,结束runWorker的while循环 return null; } // 基于ctl拿到工作线程个数 int wc = workerCountOf(c); // 核心线程允许超时,timed为true // 工作线程个数大于核心线程数,timed为true boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; if ( // 如果工作线程个数,大于最大线程数。(一般情况不会满足),把他看成false // 第二个判断代表,只要工作线程数小于等于核心线程数,必然为false // 即便工作线程个数大于核心线程数了,此时第一次循环也不会为true,因为timedOut默认值是false // 考虑第二次循环了,因为循环内部必然有修改timeOut的位置 (wc > maximumPoolSize || (timed && timedOut)) && // 要么工作线程还有,要么阻塞队列为空,并且满足上述条件后,工作线程才会走到if内部,结束工作线程 (wc > 1 || workQueue.isEmpty()) ) { // 第二次循环才有可能到这。 // 正常结束,工作线程 - 1,因为是CAS操作,如果失败了,重新走for循环 if (compareAndDecrementWorkerCount(c)) return null; continue; } // 工作线程从阻塞队列拿任务 try { // 如果是核心线程,timed是false,如果是非核心线程,timed就是true Runnable r = timed ? // 如果是非核心,走poll方法,拿任务,等待一会 workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : // 如果是核心,走take方法,死等。 workQueue.take(); // 从阻塞队列拿到的任务不为null,这边就正常返回任务,去执行 if (r != null) return r; // 说明当前线程没拿到任务,将timeOut设置为true,在上面就可以返回null退出了。 timedOut = true; } catch (InterruptedException retry) { timedOut = false; } } }
九、ThreadPoolExecutor的关闭方法
1、首先查看shutdownNow方法,可以从RUNNING状态转变为STOP
// shutDownNow方法,shutdownNow不会处理阻塞队列的任务,将任务全部给你返回了。 public List<Runnable> shutdownNow() { // 声明返回结果 List<Runnable> tasks; // 加锁 final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { // 不关注这个方法…… checkShutdownAccess(); // 将线程池状态修改为STOP advanceRunState(STOP); // 无论怎么,直接中断工作线程。 interruptWorkers(); // 将阻塞队列的任务全部扔到List集合中。 tasks = drainQueue(); } finally { // 释放锁 mainLock.unlock(); } tryTerminate(); return tasks; } // 将线程池状态修改为STOP private void advanceRunState(int STOP) { // 死循环。 for (;;) { // 获取ctl属性的值 int c = ctl.get(); // 第一个判断:如果当前线程池状态已经大于等于STOP了,不管了,告辞。 if (runStateAtLeast(c, STOP) || // 基于CAS,将ctl从c修改为STOP状态,不修改工作线程个数,但是状态变为了STOP // 如果修改成功结束 ctl.compareAndSet(c, ctlOf(STOP, workerCountOf(c)))) break; } } // 无论怎么,直接中断工作线程。 private void interruptWorkers() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { // 遍历HashSet,拿到所有的工作线程,直接中断。 for (Worker w : workers) w.interruptIfStarted(); } finally { mainLock.unlock(); } } // 移除阻塞队列,内容全部扔到List集合中 private List<Runnable> drainQueue() { BlockingQueue<Runnable> q = workQueue; ArrayList<Runnable> taskList = new ArrayList<Runnable>(); // 阻塞队列自带的,直接清空阻塞队列,内容扔到List集合 q.drainTo(taskList); // 为了避免任务丢失,重新判断,是否需要编辑阻塞队列,重新扔到List if (!q.isEmpty()) { for (Runnable r : q.toArray(new Runnable[0])) { if (q.remove(r)) taskList.add(r); } } return taskList; } // 查看当前线程池是否可以变为TERMINATED状态 final void tryTerminate() { // 死循环。 for (;;) { // 拿到ctl int c = ctl.get(); // 如果是RUNNING,直接告辞。 // 如果状态已经大于等于TIDYING,马上就要凉凉,直接告辞。 // 如果状态是SHUTDOWN,但是阻塞队列还有任务,直接告辞。 if (isRunning(c) || runStateAtLeast(c, TIDYING) || (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())) return; // 如果还有工作线程 if (workerCountOf(c) != 0) { // 再次中断工作线程 interruptIdleWorkers(ONLY_ONE); // 告辞,等你工作线程全完事,我这再尝试进入到TERMINATED状态 return; } // 加锁,为了可以执行Condition的释放操作 final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { // 将线程池状态修改为TIDYING状态,如果成功,继续往下走 if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { try { // 这个方法是空的,如果你需要在线程池关闭后做一些额外操作,这里你可以自行实现 terminated(); } finally { // 最终修改为TERMINATED状态 ctl.set(ctlOf(TERMINATED, 0)); // 线程池提供了一个方法,主线程在提交任务到线程池后,是可以继续做其他操作的。 // 咱们也可以让主线程提交任务后,等待线程池处理完毕,再做后续操作 // 这里线程池凉凉后,要唤醒哪些调用了awaitTermination方法的线程 termination.signalAll(); } return; } } finally { mainLock.unlock(); } // else retry on failed CAS } }
2、 再次shutdown方法,可以从RUNNING状态转变为SHUTDOWN
shutdown状态下,不会中断正在干活的线程,而且会处理阻塞队列中的任务
public void shutdown() { // 加锁。。 final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { // 不看。 checkShutdownAccess(); // 里面是一个死循环,将线程池状态修改为SHUTDOWN advanceRunState(SHUTDOWN); // 中断空闲线程 interruptIdleWorkers(); // 说了,这个是为了ScheduleThreadPoolExecutor准备的,不管 onShutdown(); } finally { mainLock.unlock(); } // 尝试结束线程 tryTerminate(); } // 中断空闲线程 private void interruptIdleWorkers(boolean onlyOne) { // 加锁 final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) { Thread t = w.thread; // 如果线程没有中断,那么就去获取Worker的锁,基于tryLock可知,不会中断正在干活的线程 if (!t.isInterrupted() && w.tryLock()) { try { // 会中断空闲线程 t.interrupt(); } catch (SecurityException ignore) { } finally { w.unlock(); } } if (onlyOne) break; } } finally { mainLock.unlock(); } }