ThreadPoolExecutor继承关系如下所示:
Executor是顶层接口,内部定义了唯一方法execute(Runnable command),用来表示一个线程执行调度的工具,具体实现如下:
public interface Executor {
void execute(Runnable command);
}
在Executor基础上,定义了ExecutorService接口,内部定义了多线程操作的丰富工具方法,源码定义如下:
public interface ExecutorService extends Executor {
/**
*在之前提交的,需要被执行的任务中,有序的进行关闭操作,并且此时不会再接受新的任务
* 如果此时所有的任务已经关闭的话,那么就不会起到什么效果,因为已经没有任务可关闭了
*/
void shutdown();
/**
* 企图关闭所有正在执行的任务,并且中断正在等待要执行的任务,返回一个包含正在等待的任务的列表
*/
List<Runnable> shutdownNow();
/**
* 如果线程已经关闭了,就返回true
*/
boolean isShutdown();
/**
* 如果所有的线程任务已经关闭了,就返回true
*/
boolean isTerminated();
/**
* 只有当所有的任务都成功执行,否则会一直处于阻塞状态,只有当一下情况发生时,才会中断阻塞
* 例如收到一个关闭的请求,或者超时发生、或者当前的线程被中断后
*/
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
/**
* 提交一个需要返回结果的任务去执行,返回一个有结果的消息体,只有成功执行后,才会返回结果
*/
<T> Future<T> submit(Callable<T> task);
/**
* 只有当任务成功被执行后,才会返回给定的结果
*/
<T> Future<T> submit(Runnable task, T result);
/**
* 执行Runaable任务,调用Future#get()会堵塞直到完成,返回一个空结果
*/
Future<?> submit(Runnable task);
/**
* 提交一批任务,并返回一批任务的结果列表
*/
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;
/**
* 提交一批任务,并返回一批任务的结果列表
* 存在超时时间,如果任务在超时时间内未完成,会被取消。
*/
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
/**
* 提交一批任务信息,当其中一个成功的执行,没有返回异常的时候,就返回结果
*/
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
/**
* 提交一批任务信息,当其中一个成功的执行,没有返回异常的时候,就返回结果
* 有超时时间,如果没有任务在超时时间前完成,会抛出TimeoutException
*/
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
再往上,AbstractExecutorService抽象类实现了ExecutorService接口,提供了一些基础方法实现。
下面开始看ThreadPoolExecutor,ThreadPoolExecutor实现了,AbstractExecutorService抽象类,内部定义了众多的成员属性,相关源码定义如下:
public class ThreadPoolExecutor extends AbstractExecutorService {
// 线程池的控制状态(用来表示线程池的运行状态(整形的高3位)和运行的worker数量(低29位))
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 29位的偏移量
private static final int COUNT_BITS = Integer.SIZE - 3;
// 最大容量(2^29 - 1)
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
// 线程运行状态,总共有5个状态,需要3位来表示(所以偏移量的29 = 32 - 3)
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
// 阻塞队列
private final BlockingQueue<Runnable> workQueue;
// 可重入锁
private final ReentrantLock mainLock = new ReentrantLock();
// 存放工作线程集合
private final HashSet<Worker> workers = new HashSet<Worker>();
// 终止条件
private final Condition termination = mainLock.newCondition();
// 最大线程池容量
private int largestPoolSize;
// 已完成任务数量
private long completedTaskCount;
// 线程工厂
private volatile ThreadFactory threadFactory;
// 拒绝执行处理器
private volatile RejectedExecutionHandler handler;
// 线程等待运行时间
private volatile long keepAliveTime;
// 是否运行核心线程超时
private volatile boolean allowCoreThreadTimeOut;
// 核心池的大小
private volatile int corePoolSize;
// 最大线程池大小
private volatile int maximumPoolSize;
// 默认拒绝执行处理器
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
}
在成员变量中,有一个非常重要的内部属性ctl,ctl为线程池的控制状态,用来表示线程池的运行状态(整形的高3位)和运行的worker数量(低29位)),其中,线程池的运行状态有如下几种:
/**
* RUNNING : 接受新任务并且处理已经进入阻塞队列的任务
* SHUTDOWN : 不接受新任务,但是处理已经进入阻塞队列的任务
* STOP : 不接受新任务,不处理已经进入阻塞队列的任务并且中断正在运行的任务
* TIDYING : 所有的任务都已经终止,workerCount为0, 线程转化为TIDYING状态并且调用terminated钩子函数
* TERMINATED: terminated钩子函数已经运行完成
**/
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
说明:由于有5种状态,最少需要3位表示,所以采用的AtomicInteger的高3位来表示,低29位用来表示worker的数量,即最多表示2^29 - 1。
除了核心内部属性ctl外,ThreadPoolExecutor还定义了一部分对外用于线程池调优的核心属性:
以上参数可以通过ThreadPoolExecutor的构造函数来初始化:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
workQueue可以为以下常见的堵塞队列类型,以让线程池具备不同的特性:
4)ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。如:
ThreadFactory myThreadFacotry = new ThreadFactoryBuilder().setNameFormat("myTask-%d").build();
当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。在ThreadPoolExecutor中,定义了以下4种策略:
相关源码实现如下:
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
/**
* 先判断如果线程池不是关闭状态,表示可以接受处理新任务
* 这个时候尝试用当前线程来运行
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
/**
* 直接抛出异常
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
/**
* 不做任何事情,表示直接丢弃
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
/**
* 先判断如果线程池不是关闭状态,表示可以接受处理新任务
* 从线程池工作队列中丢弃最老的队列(先进先出),而后用线程池调度当前任务
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化存储不能处理的任务。
如果在系统中大量使用线程池,则有必要对线程池进行监控,方便在出现问题时,可以根据线程池的使用状况快速定位问题。可以通过线程池提供的参数进行监控,在监控线程池的时候可以使用以下属性。
我们可以基于Executors工具类来简化以上参数定义,来辅助创建特定用途的线程池:
ThreadPoolExecutor执行execute方法的处理流程如下:
进一步,线程池运行过程涉及到一些核心成员变量,主要使用流程如下:
示意图如下所示:
下面分析下源码实现:
public void execute(Runnable command) {
if (command == null) // 命令为null,抛出异常
throw new NullPointerException();
// 获取线程池控制状态
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) { // worker数量小于corePoolSize
// 创建新的线程来执行command
if (addWorker(command, true)) // 添加worker
// 成功则返回
return;
// 不成功则再次获取线程池控制状态
c = ctl.get();
}
/** 如果一个任务能够成功入队列,在添加一个线程时仍需要进行双重检查(因为在前一次检查后该线程死亡了)
* 或者当进入到此方法时,线程池已经shutdown了,所以需要再次检查状态,
* 若有必要,当停止时还需要回滚入队列操作,或者当线程池没有线程时需要创建一个新线程
*/
if (isRunning(c) && workQueue.offer(command)) { // 线程池处于RUNNING状态,将命令(用户自定义的Runnable对象)添加进workQueue队列
// 再次检查,获取线程池控制状态
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command)) // 线程池不处于RUNNING状态,将命令从workQueue队列中移除
// 拒绝执行命令
reject(command);
else if (workerCountOf(recheck) == 0) // worker数量等于0
// 添加worker,必要扩展线程池线程数大于核心线程数
addWorker(null, false);
}
else if (!addWorker(command, false)) // 向队列中添加失败,说明队列已满,尝试添加worker,必要扩展线程池线程数大于核心线程数
// 添加失败,拒绝执行命令,说明线程池已到最大线程数
reject(command);
}
// 获取工作的线程数
private static int workerCountOf(int c) {
return c & CAPACITY;
}
// 是否在运行中
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
// 根据handle执行相关拒绝策略
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
从源码中看到,实际提交任务是在addWorker函数中完成:
此函数可能会完成如下几件任务
具体源码如下:
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) { // 死循环尝试添加任务
// 有两层循环,外层循环主要检查线程状态。
// 获取线程池控制状态
int c = ctl.get();
// 获取状态,c & ~CAPACITY,即获取高3位
int rs = runStateOf(c);
// 检查线程池非运行状态或处于正在关闭状态且队列为空,这两种情况直接返回失败
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
// worker数量
int wc = workerCountOf(c);
if (wc >= CAPACITY || // worker数量大于等于最大容量
wc >= (core ? corePoolSize : maximumPoolSize)) // worker数量大于等于核心线程池大小或者最大线程池大小
// 超额返回添加失败
return false;
// cas尝试添加worker
if (compareAndIncrementWorkerCount(c))
// 跳出外层循环,表示添加成功
break retry;
// 添加失败,获取线程池控制状态
c = ctl.get();
if (runStateOf(c) != rs) // 二次确认
// 运行状态发生变化,从外层循环从新开始,重新获取运行状态
continue retry;
// 走到这里,说明cas失败,可能有并发线程提交任务修改了workerCount,这里继续进行内层循环
}
}
// worker开始标识
boolean workerStarted = false;
// worker被添加标识
boolean workerAdded = false;
Worker w = null;
try {
// 初始化worker,获取线程工厂初始化一个新线程
w = new Worker(firstTask);
// 获取worker对应的线程
final Thread t = w.thread;
if (t != null) { // 线程不为null
// 线程池锁
final ReentrantLock mainLock = this.mainLock;
// 获取锁
mainLock.lock();
try {
// 线程池的运行状态
int rs = runStateOf(ctl.get());
// 作二次状态检查
if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // alive状态代表已经启动且未结束, 线程刚添加进来,还未启动就存活,说明存在异常
throw new IllegalThreadStateException();
// 将worker添加到worker集合
workers.add(w);
// 获取worker集合的大小
int s = workers.size();
// 记录线程池曾经达到的最大线程数
if (s > largestPoolSize) // 队列大小大于largestPoolSize
// 重新设置largestPoolSize
largestPoolSize = s;
// 设置worker已被添加标识
workerAdded = true;
}
} finally {
// 释放锁
mainLock.unlock();
}
if (workerAdded) { // worker被添加
// 开始执行worker的run方法
t.start();
// 设置worker已开始标识
workerStarted = true;
}
}
} finally {
if (! workerStarted) // worker没有开始
// 添加worker失败,进行回滚
addWorkerFailed(w);
}
return workerStarted;
}
// 创建一个Worker的代码如下
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
// 根据线程工厂创建线程
this.thread = getThreadFactory().newThread(this);
}
// 在添加失败后要进行回滚
/**
* Rolls back the worker thread creation.
* - removes worker from workers, if present
* - decrements worker count
* - rechecks for termination, in case the existence of this
* worker was holding up termination
*/
private void addWorkerFailed(Worker w) {
// 操作workers需要加锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
// 如果存在则移除
workers.remove(w);
// 存在并发可能,cas 死循环减少ctl workers数
decrementWorkerCount();
// 尝试终止线程
tryTerminate();
} finally {
mainLock.unlock();
}
}
// 存在并发可能,cas 死循环减少ctl workers数
private void decrementWorkerCount() {
do {} while (! compareAndDecrementWorkerCount(ctl.get()));
}
从上面的实现中,我们可以看到execute方法并未真正执行我们command的run方法,而是根据需要创建worker线程或将任务放到workerQueue中,由已经创建的worker线程从workerQueue中获取任务执行。下面看看Worker工作线程的定义以及通过源码看它是怎么实现每个任务调度、执行的过程。
工作线程:线程池创建线程时,会将线程封装成工作线程Worker,Worker在执行完任务后,还会循环获取工作队列里的任务来执行。
Worker的属性定义如下:
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable {
// 版本号
private static final long serialVersionUID = 6138294804551838833L;
// worker 所对应的线程
final Thread thread;
// worker所对应的第一个任务
Runnable firstTask;
// 已完成任务数量
volatile long completedTasks;
}
Worker实现了Runnable接口,下面看看内部方法的整体实现
// Worker的run方法,在线程池execute方法中真正创建子线程执行的方法
public void run() {
runWorker(this);
}
// 下面是基于AQS的相关实现方法
// 是否被独占,0代表未被独占,1代表被独占
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) {
// 设置独占线程为null
setExclusiveOwnerThread(null);
// 设置状态为0
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(); }
//
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) { // AQS状态大于等于0并且worker对应的线程不为null并且该线程没有被中断
try {
// 中断线程
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
从上看到,在Wroker中,实现了一个独占式不可重入锁。在核心run方法中,主要调用了ThreadPoolExecutor中定义的runWorker方法:
final void runWorker(Worker w) {
// 获取当前线程
Thread wt = Thread.currentThread();
// 获取w的firstTask
Runnable task = w.firstTask;
// 设置w的firstTask为null
w.firstTask = null;
// 释放锁(设置state为0,允许中断)
w.unlock();
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) { // 任务不为null或者阻塞队列还存在任务
// 获取锁
w.lock();
// 如果worker线程没有被打断,但是检查(包括二次检查)运行状态在STOPPING之后,则冲断worker线程
if ((runStateAtLeast(ctl.get(), STOP) || // 线程池的运行状态至少应该高于STOP
(Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && // 再次检查,线程池的运行状态至少应该高于STOP
!wt.isInterrupted()) // wt线程(当前线程)没有被中断
wt.interrupt(); // 中断wt线程(当前线程)
try {
// 在执行之前调用钩子函数
beforeExecute(wt, task);
Throwable thrown = null;
try {
// 运行给定的任务,注意这里执行的是run方法,没有另开子线程执行任务。
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;
// 增加给worker完成的任务数量
w.completedTasks++;
// 释放锁
w.unlock();
}
}
completedAbruptly = false;
} finally {
// 处理完成后,调用钩子函数
processWorkerExit(w, completedAbruptly);
}
}
在循环执行每个任务开始,通过getTask获取要运行的任务:
private Runnable getTask() {
boolean timedOut = false; // 用于后续标识从工作队列中堵塞获取任务是否超时
for (;;) { // 无限循环,确保操作成功
// 获取线程池控制状态
int c = ctl.get();
// 运行的状态
int rs = runStateOf(c);
// 如果线程池在关闭状态往后,且工作队列为空,说明不再接受任务处理,结束worker处理任务流程
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { // 大于等于SHUTDOWN(表示调用了shutDown)并且(大于等于STOP(调用了shutDownNow)或者worker阻塞队列为空)
// 减少worker的数量
decrementWorkerCount();
// 返回null,不执行任务
return null;
}
// 获取worker数量
int wc = workerCountOf(c);
// 是否允许coreThread超时或者workerCount大于核心大小
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// worker数量大于maximumPoolSize,或者从任务队列获取超时并且上面timed为true,同时工作线程数大于1或者worker阻塞队列为空
// 满足这个条件,说明非核心工作线程到达指定空闲时间,尝试销毁
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {// 在阻塞队列不为空时,需要保证至少有一个wc
if (compareAndDecrementWorkerCount(c)) // 比较并减少workerCount
// 减少成功,返回null,不执行任务,该worker会退出
return null;
// 跳过剩余部分,继续循环走上面流程
continue;
}
// 如果允许核心线超时回收,或当前线程数超过核心线程,会在超时时间内获取,获取失败则回收线程,否则一直等待直到有元素
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : // 等待指定时间
workQueue.take(); // 一直等待,直到有元素
// 有任务调度,直接返回要执行的任务
if (r != null)
return r;
// 等待指定时间后,没有获取元素,则超时
timedOut = true;
} catch (InterruptedException retry) {
// 抛出了被中断异常,重试,没有超时
timedOut = false;
}
}
}
在上面尝试获取任务的同时,实现了线程池线程的空闲管理逻辑,如空闲一段时间内未获取到线程,会返回空,完成工作线程结束操作。
运行过程涉及到三个钩子函数:
下面看看processWorkerExit实现,执行到这一步有两种可能:
满足上面任一条件后,会执行processWorkerExit完成工作线程退出操作:
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // 如果被中断,则需要减少workCount,否则这一步已经在前面完成
decrementWorkerCount();
// 获取可重入锁,用于修改workers集合
final ReentrantLock mainLock = this.mainLock;
// 获取锁
mainLock.lock();
try {
// 将worker完成的任务添加到总的完成任务中
completedTaskCount += w.completedTasks;
// 从workers集合中移除该worker
workers.remove(w);
} finally {
// 释放锁
mainLock.unlock();
}
// 尝试终止
tryTerminate();
// 获取线程池控制状态
int c = ctl.get();
if (runStateLessThan(c, STOP)) { // 小于STOP的运行状态
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty()) // 允许核心超时并且workQueue阻塞队列不为空
// 确保最少线程至少有一个
min = 1;
if (workerCountOf(c) >= min) // workerCount大于等于min,说明当前线程可以安全结束
// 直接返回
return;
}
// 添加worker,表示需要保留当前worker,通过新建一个替代当前实现
addWorker(null, false);
}
}
可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池。它们的原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。只要调用了这两个关闭方法中的任意一个,isShutdown方法就会返回true。当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。
但是它们存在一定的区别,shutdownNow首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表,而shutdown只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。
至于应该调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown方法来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow方法。
public void shutdown() {
// 加锁操作
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 检查shutdown权限
checkShutdownAccess();
// 设置线程池控制状态为SHUTDOWN
advanceRunState(SHUTDOWN);
// 中断空闲worker
interruptIdleWorkers();
// 调用shutdown钩子函数
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
// 尝试终止
tryTerminate();
}
在整个尝试关闭过程,进行了5步操作:
下面依次分析每一步实现
如果存在安全管理器,确保调用方有权限关闭每一个线程
private void checkShutdownAccess() {
// 获取系统安全管理器
SecurityManager security = System.getSecurityManager();
if (security != null) {
// 检查关闭权限
security.checkPermission(shutdownPerm);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
// 检查每个线程的访问权限
security.checkAccess(w.thread);
} finally {
mainLock.unlock();
}
}
}
不断自旋cas操作,确保线程池在指定状态之后或者尝试将线程池更新到指定状态成功,在shutdown调用中为SHUTDOWN状态。
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
// 在指定状态前或者更新到指定状态成功则中断
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 遍历所有worker,如果worker已经启动,尝试进行中断
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
// 调用一下方法来中断启动的工作线程,期间会检查工作线程是否处于工作状态,只终止不处于工作状态的工作线程。
void interruptIfStarted() {
Thread t;
// getState() >= 0,说明当前线程没有执行任务,在尝试从任务队列中获取任务,即代表空闲worker
// 如果线程没有被中断,则尝试中断线程
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
在ThreadPoolExecutor默认实现中,这是一个空实现,供子类拓展:
void onShutdown() {
}
final void tryTerminate() {
for (;;) { // 无限循环,确保操作成功
// 获取线程池控制状态
int c = ctl.get();
// 检查当前线程池的状态和任务调度情况是否满足转化为终止状态,如果满足以下任意条件则不进行终止
// 1. 线程池的运行状态为RUNNING
// 2. 线程池的运行状态在TIDYING之前
// 3. 线程池的运行状态为SHUTDOWN但workQueue队列不为null
if (isRunning(c) || // 线程池的运行状态为RUNNING
runStateAtLeast(c, TIDYING) || // 或者线程池的运行状态最小要大于TIDYING
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())) // 或者线程池的运行状态为SHUTDOWN但workQueue队列不为null
// 不能终止,直接返回
return;
if (workerCountOf(c) != 0) { // 线程池仍有继续运行的必要
// 注意tryTerminate也可能在一个worker线程需要回收的时候调用
// 这个时候会触发这里的逻辑,仅仅中断一个空闲的worker。
interruptIdleWorkers(ONLY_ONE);
return;
}
// 获取线程池的锁
final ReentrantLock mainLock = this.mainLock;
// 获取锁
mainLock.lock();
try {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { // 比较并设置线程池控制状态为TIDYING
try {
// 终止,钩子函数,
terminated();
} finally {
// 设置线程池控制状态为TERMINATED
ctl.set(ctlOf(TERMINATED, 0));
// 释放在termination条件上等待的所有线程,这些线程一般都是正在执行awaitTermination函数。
termination.signalAll();
}
return;
}
} finally {
// 释放锁
mainLock.unlock();
}
// 存在并发操作导致期间cas失败,继续循环操作
}
}
中断一个空闲线程的操作interruptIdleWorkers实现如下:
private void interruptIdleWorkers(boolean onlyOne) {
// 线程池的锁
final ReentrantLock mainLock = this.mainLock;
// 获取锁
mainLock.lock();
try {
for (Worker w : workers) { // 遍历workers队列
// worker对应的线程
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) { // 线程未被中断并且成功获得锁
try {
// 中断线程
t.interrupt();
} catch (SecurityException ignore) {
} finally {
// 释放锁
w.unlock();
}
}
if (onlyOne) // 若只中断一个,则跳出循环
break;
}
} finally {
// 释放锁
mainLock.unlock();
}
}
前面提到,shutdownNow方法和shutdown方法的主要区别是shutdownNow首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表,而shutdown只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。
下面看看shutdownNow的实现:
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
// 更新为STOP状态
advanceRunState(STOP);
interruptWorkers();
// 获取所有工作队列中的线程
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
private List<Runnable> drainQueue() {
// 缓存本地
BlockingQueue<Runnable> q = workQueue;
ArrayList<Runnable> taskList = new ArrayList<Runnable>();
// 将队列中值,全部移除,并发设置到给定的集合中。
q.drainTo(taskList);
// 工作队列不为空,queue为DelayQueue或其他类型队列drainTo操作会移除一部分元素失败
// 因而需要在下面一个个移除
if (!q.isEmpty()) {
for (Runnable r : q.toArray(new Runnable[0])) {
if (q.remove(r))
taskList.add(r);
}
}
return taskList;
}
如果执行了shutdonw或shutdownNow操作,线程池不会立即终止,可以通过调用awaitTermination方法尝试堵塞指定时长,直到超时或线程池完成终止
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
// 转换指定单位的时长。
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (;;) {
// 判断是终止状态,则返回终止成功
if (runStateAtLeast(ctl.get(), TERMINATED))
return true;
// 传入时间参数无效,返回false
if (nanos <= 0)
return false;
// 条件堵塞,直到被唤醒或到达nanos超时时间
nanos = termination.awaitNanos(nanos);
}
} finally {
mainLock.unlock();
}
}