ThreadPoolExecutor源码分析
继承体系图
线程池内部结构图
线程池状态转换图
重要属性以及常量说明
/*
* 表示两种含义
* 1. 高3位表示当前线程池运行状态
* 2. 低29位表示当前线程池中所拥有的线程数量
*/
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 表示ctl中,低COUNT_BITS位,用于存放当前数量的位。(主要是为了防止int在某个JDK版本不是4个byte)
private static final int COUNT_BITS = Integer.SIZE - 3;
// 表示ctl低位所能表达的最大数值(高3个0 低29个1)
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// 11100000000000000000000000000000 接收新任务,也处理阻塞队列里的任务
private static final int RUNNING = -1 << COUNT_BITS;
// 32个0 不接受新任务,但是处理阻塞队列中的任务
private static final int SHUTDOWN = 0 << COUNT_BITS;
// 00100000000000000000000000000000 不接受新任务,不处理阻塞队列中的任务,中断处理中的任务
private static final int STOP = 1 << COUNT_BITS;
// 01000000000000000000000000000000 当所有任务执行完了,当前线程池没有工作线程,调用terminated方法
private static final int TIDYING = 2 << COUNT_BITS;
// 01100000000000000000000000000000 调用terminated方法完成
private static final int TERMINATED = 3 << COUNT_BITS;
// 任务队列
private final BlockingQueue<Runnable> workQueue;
// 线程池全局锁,增加worker,减少worker,修改线程池运行状态,都需要这把锁
private final ReentrantLock mainLock = new ReentrantLock();
// 线程池中真正存放 worker 的地方
private final HashSet<Worker> workers = new HashSet<Worker>();
// 条件队列,当外部线程调用 awaitTermination()方法时,外部线程会等待当前线程池状态为Termination为止
private final Condition termination = mainLock.newCondition();
// 记录线程池生命周期内,线程最大数值
private int largestPoolSize;
// 记录线程池所完成任务总数,当worker退出时将worker完成的任务数量累加到completedTaskCount
private long completedTaskCount;
// 创建线程时会使用线程工厂
private volatile ThreadFactory threadFactory;
// 拒绝策略
private volatile RejectedExecutionHandler handler;
// 空闲线程存活时间
private volatile long keepAliveTime;
// 当为true时会根据keepAliveTime核心线程也会被回收
private volatile boolean allowCoreThreadTimeOut;
// 核心线程数量
private volatile int corePoolSize;
// 最大线程数量
private volatile int maximumPoolSize;
// 默认的拒绝策略
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
// 权限相关的属性
private static final RuntimePermission shutdownPerm = new RuntimePermission("modifyThread");
// 权限相关的属性
private final AccessControlContext acc;
非核心方法解析
runStateOf
1.源代码
private static int runStateOf(int c) { return c & ~CAPACITY; }
2.方法说明
获取当前线程池运行状态
workerCountOf
1.源代码
private static int workerCountOf(int c) { return c & CAPACITY; }
2.方法说明
获取当前线程池线程数量
ctlOf
1.源代码
private static int ctlOf(int rs, int wc) { return rs | wc; }
2.方法说明
用在重置当前线程ctl时会用到
3.方法入参
- rs: 表示线程池状态
- wc: 表示当前线程池中worker数量
runStateLessThan
1.源代码
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
2.方法说明
比较当前线程池ctl所表示的状态,是否小于某个状态s
3.方法入参
- c: ctl
- s: 某个状态
runStateAtLeast
1.源代码
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
2.方法说明
比较当前线程池ctl所表示的状态,是大于等于于某个状态s
isRunning
1.源代码
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
2.方法说明
当前线程池状态是不是RUNNING
compareAndIncrementWorkerCount
1.源代码
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect + 1);
}
2.方法说明
使用AtomicInteger的compareAndSet让ctl加1如果成功返回true,失败返回false
compareAndDecrementWorkerCount
1.源代码
private boolean compareAndDecrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect - 1);
}
2.方法说明
使用AtomicInteger的compareAndSet让ctl减1如果成功返回true,失败返回false
decrementWorkerCount
1.源代码
private void decrementWorkerCount() {
do {} while (! compareAndDecrementWorkerCount(ctl.get()));
}
2.方法说明
将ctl-1,这个方法一定会-1成功
构造方法解析
1.源代码
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;
}
2.方法入参说明
- corePoolSize: 核心线程数量
- maximumPoolSize: 最大线程数量
- keepAliveTime: 非核心线程的存活时间
- unit: 时间单位
- workQueue: 存放Runnable的阻塞队列
- threadFactory: 用来创建线程的工厂
- handler: 拒绝策略
3.方法作用说明
初始化各种属性
addWorkerFailed
1.源代码
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
// 持有全局锁,因为要操作workers
mainLock.lock();
try {
if (w != null)
workers.remove(w);
// ctl-1
decrementWorkerCount();
tryTerminate();
} finally {
// 解锁
mainLock.unlock();
}
}
2.方法作用
添加worker失败后的扫尾方法,负责把worker从workers中移除和线程数量-1
advanceRunState
1.源代码
private void advanceRunState(int targetState) {
// 自旋
for (;;) {
// ctl
int c = ctl.get();
/*
* 1. runStateAtLeast(c, targetState)——当前状态是否大于等于指定状态
* 2. ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))——使用CAS设置ctl为新值
*/
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
2.方法说明
设置线程池状态为指定状态
interruptIdleWorkers
1.源代码
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
// 加锁
mainLock.lock();
try {
// 遍历所有worker
for (Worker w : workers) {
// 获取每个worker的线程
Thread t = w.thread;
/*
* 1. !t.isInterrupted()——当前迭代没有被打断
* 2. w.tryLock()——能获取到锁说明当前worker是空闲线程
*/
if (!t.isInterrupted() && w.tryLock()) {
try {
// 打断
t.interrupt();
} catch (SecurityException ignore) {
} finally {
// 解锁
w.unlock();
}
}
// 如果是true只打断一个
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
2.方法说明
根据方法入参决定打断一个空闲线程还是所有false打断所有空闲线程
核心内部类解析
Worker
1.源代码
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
private static final long serialVersionUID = 6138294804551838833L;
// worker内部封装的Thread
final Thread thread;
// 假设firstTask不为空,那么当worker启动后(内部的线程启动)会优先执行firstTask,当执行完firstTask后,会到queue中去获取下一个任务
Runnable firstTask;
// 记录当前worker所完成任务数量
volatile long completedTasks;
/*
* 构造方法
* 1. firstTask参数可以为空
* 2. firstTask参数为null,那么worker启动后会到queue中获取
*/
Worker(Runnable firstTask) {
// 设置AQS独占模式为初始化中状态,这个时候,不能被抢占
setState(-1);
// 初始化firstTask
this.firstTask = firstTask;
// 使用线程工厂创建一个线程,并且将当前worker指定为Runnable,也就是属性thread的start方法会执行当前worker类的run方法
this.thread = getThreadFactory().newThread(this);
}
// worker启动 会执行这个
public void run() {
runWorker(this);
}
// 判断当前worker的独占锁是否被占有
protected boolean isHeldExclusively() {
return getState() != 0;
}
// 尝试去占用worker的独占锁
protected boolean tryAcquire(int unused) {
// 使用CAS抢占锁
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); }
// 一般情况下调用这个方法是要持有锁的,当worker的state为-1时,调用unlock表示初始化state设置为0
// 启动worker之后会先调用unlock方法,会强制刷新锁的持有线程为null和state为0
public void unlock() { release(1); }
// 当前worker的Lock是否被占用
public boolean isLocked() { return isHeldExclusively(); }
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
2.属性说明
- thread: worker内部封装的Thread
- firstTask: 优先启动的任务
- completedTasks: 记录当前worker所完成任务数量
构造方法解析
源代码
Worker(Runnable firstTask) {
setState(-1);
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
方法作用说明
初始化继承自AQS的state,firstTask,thread属性
run方法解析
源代码
public void run() {
runWorker(this);
}
方法作用说明
worker启动后这个方法为入口
isHeldExclusively方法解析
源代码
protected boolean isHeldExclusively() {
return getState() != 0;
}
方法作用说明
判断当前worker的独占锁是否被占有
tryAcquire方法解析
源代码
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
方法作用说明
尝试去占有worker的独占锁
tryRelease方法解析
源代码
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
方法作用说明
尝试去释放锁
lock方法解析
源代码
public void lock() { acquire(1); }
方法作用说明
加锁,加锁失败会阻塞当前线程,直到获得锁为止
tryLock方法解析
源代码
public boolean tryLock() { return tryAcquire(1); }
方法作用说明
尝试加锁
unlock方法解析
源代码
public void unlock() { release(1); }
方法作用说明
一般情况下调用这个方法是要持有锁的,当worker的state为-1时,调用unlock表示初始化state设置为0
启动worker之后会先调用unlock方法,会强制刷新锁的持有线程为null和state为0
isLocked方法解析
源代码
public boolean isLocked() { return isHeldExclusively(); }
方法作用说明
当前worker的Lock是否被占用
核心方法execute解析
1.源代码
public void execute(Runnable command) {
// 非空判断
if (command == null)
throw new NullPointerException();
// 获取属性ctl的值
int c = ctl.get();
// 条件成立:当前线程池中的线程数量小于核心线程数量
if (workerCountOf(c) < corePoolSize) {
// 创建一个新的worker,并且将command作为firstTask
// true表示创建的是核心线程
if (addWorker(command, true))
return;
/*
* 执行到这里说明创建worker失败
* 1. 第一种原因:存在并发情况导致线程池中的线程数里已经不小于核心线程数量了
* 2. 第二种原因:线程池状态发生改变,线程池状态非RUNNING一般都会失败除了后面那种特殊情况,SHUTDWON状态下有可能创建成功但是比如firstTask是null并且queue不为空
*/
// 重新获取属性ctl的值
c = ctl.get();
}
/*
* 执行到这里的原因
* 1. 当前线程数量大于等于核心线程数量
* 2. addWorker失败
*/
// 如果线程池是RUNNING状态则尝试把任务加到任务队列中
if (isRunning(c) && workQueue.offer(command)) {
// 再次获取ctl
int recheck = ctl.get();
// 如果线程池不是RUNNING状态则尝试删除刚刚提交的任务,如果删除成功
if (! isRunning(recheck) && remove(command))
// 调用拒绝策略
reject(command);
/*
* 有几种情况会来到这里
* 1. 当前线程池是RUNNING状态
* 2. 线程池是非RUNNING状态,但是移除任务失败,这种情况其实不用管,主要解决的问题是第一种情况
*/
// 防止虽然线程池是RUNNING状态,但是线程数量是0
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
/*
* 1. offer失败——说明队列满了需要开启救急线程如果没有达到最大线程数量
* 2. 当前线程池非RUNNING状态——执行拒绝策略
* 3. addWorker失败——线程数量达到最大线程数量
*/
else if (!addWorker(command, false))
reject(command);
}
2.情况说明
- 线程池中的线程数量<核心线程数量
- 任务加入阻塞队列,但是线程池状态不同
- 线程池是running状态
- 线程池不是running状态
- 线程池不是running状态
- 加入阻塞队列失败并且线程数量达到最大值
情况1:线程池中的线程数量<核心线程数量
源代码
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
代码分析
- 如果满足情况则取尝试添加核心线程让核心线程去处理这个任务
- 添加核心线程可能会失败原因如下
- 线程池状态发生改变造成添加worker失败(SHUTDOWN状态可能创建成功,具体看addWorker方法分析)
- 其他线程已经添加过worker并且worker数量已经大于核心线程数量了
情况2:任务加入阻塞队列,线程池是running状态
源代码
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
代码分析
- 如果线程池是running状态那么尝试添加任务到阻塞队列中则结束
- 后续流程是用来处理任务加入阻塞队列但是线程池状态不是running的情况
情况3:任务加入阻塞队列,线程池不是running状态
源代码
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
代码分析
- 如果线程池状态不是running状态则尝试从阻塞队列中移除任务
- 移除成功:执行拒绝策略
- 移除失败:如果线程池中的线程数量是0那么尝试添加一个救急线程去处理
情况4:线程池不是running状态
源代码
else if (!addWorker(command, false))
reject(command);
代码分析
- 不是running状态则去执行addWorker方法如果失败(一定会失败)去执行拒绝策略
- 一定会失败也就是说如果线程池不是running状态则去执行拒绝策略
情况5:加入阻塞队列失败并且线程数量达到最大值
源代码
else if (!addWorker(command, false))
reject(command);
代码分析
如果线程池线程数量达到最大值那么addWorker方法一定会失败那么就会执行拒绝策略,反过来说就是没有达到最大线程数量就会添加worker成功不去执行拒绝策略
核心方法addWorker解析
1.源代码
private boolean addWorker(Runnable firstTask, boolean core) {
// 这个自旋用来判断当前线程是否能够创建worker
retry:
for (;;) {
// 引用属性ctl
int c = ctl.get();
// 获取线程池的状态
int rs = runStateOf(c);
/*
* 判断那些状态可以去添加worker,如果状态不对直接返回
* 1. running状态
* 2. 状态是shutdown,firstTask是null,阻塞队列不是null
*/
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
// 自旋
for (;;) {
// 获取当前线程池中的线程数量
int wc = workerCountOf(c);
/*
* 1. wc >= CAPACITY——线程数量是否超过最大值(永远不会成立因为没有电脑能达到这个上限5亿多)
* 2. wc >= (core ? corePoolSize : maximumPoolSize)——线程数量是否大于核心线程数量或最大线程数量(这取决与入参)
*/
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 条件成立:使用CAS让ctl+1(也就是线程数量+1)
if (compareAndIncrementWorkerCount(c))
break retry;
// 走到这里说明compareAndIncrementWorkerCount失败了也就是ctl发生了改变要获取ctl最新值
c = ctl.get();
// 条件成立:说明线程池的状态发生了改变,需要自旋再次走判断
if (runStateOf(c) != rs)
continue retry;
}
}
// 表示当前创建的worker是否启动
boolean workerStarted = false;
// 表示创建的worker是否添加到池子中
boolean workerAdded = false;
// 要创建的Worker的引用
Worker w = null;
try {
// 创建worker
w = new Worker(firstTask);
// 拿到worker里面的thread
final Thread t = w.thread;
// 基本不会是null,之所以有这个判断是因为ThreadFactory是个接口谁都可以实现防止有bug
if (t != null) {
// 获取全局锁
final ReentrantLock mainLock = this.mainLock;
// 上锁
mainLock.lock();
try {
// 再次获取线程池状态
int rs = runStateOf(ctl.get());
/*
* 1. rs < SHUTDOWN——线程池为running状态
* 2. (rs == SHUTDOWN && firstTask == null)——当前状态为shutdown并且firstTask是null
*/
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 条件成立:防止自定义的ThreadFactory在返回Thread之前将线程start了
if (t.isAlive())
throw new IllegalThreadStateException();
// 将创建的worker添加到线程池中
workers.add(w);
// 获取线程池线程数量
int s = workers.size();
// 条件成立:说明达到历史最大线程数更新以下largestPoolSize
if (s > largestPoolSize)
largestPoolSize = s;
// 表示线程已经进入线程池中
workerAdded = true;
}
} finally {
// 释放锁
mainLock.unlock();
}
// 如果成立说明worker已在池子中,反过来说就是添加失败(在lock之前线程池状态发生了改变导致的)
if (workerAdded) {
// 启动线程
t.start();
// 设置启动标记为ture
workerStarted = true;
}
}
} finally {
// 条件成立:启动标记是false,说明添加标记也是false
if (! workerStarted)
// 条件失败做收尾工作,线程数量-1,在workers中移除
addWorkerFailed(w);
}
return workerStarted;
}
2.入参说明
- firstTask: 新添加的worker首先要执行的任务
- core: 是否是核心线程
3.方法变量说明
- c: ctl
- rs: 线程池状态
- wc: 线程池中的线程数量
- workerStarted: worker是否启动的标记
- workerAdded: worker是否加入到池中的标记
- t: Worker类内部的Thread
4.情况说明
- 那些情况不能添加worker
- 状态为stop,tidying,terminated不能添加worker
- 状态是shutdown,firstTask不是null或阻塞队列是空的
- 线程池中线程数量超过最大值
- 线程池中线程数量超过核心线程数或最大线程数
- 尝试将ctl+1(线程池中的线程数量+1)失败了
- 添加worker逻辑
- 全局锁加锁
- 将worker添加到workers中
- 启动worker
- 如果没添加成功进行扫尾工作
核心方法runWorker解析
1.源代码
final void runWorker(Worker w) {
// w.thread是一个引用
Thread wt = Thread.currentThread();
// 引用fristTask
Runnable task = w.firstTask;
w.firstTask = null;
// 调用unlock初始化worker的state与exclusiveOwnerThread属性
w.unlock();
// 表示是否是突然退出,true表示发生异常当前线程是突然退出的,false表示正常退出
boolean completedAbruptly = true;
try {
/*
* 有任务执行的情况
* 1. task != null——firTask不是null去执行
* 2. (task = getTask()) != null——当前线程从阻塞队列中成功获取了任务去执行
*/
while (task != null || (task = getTask()) != null) {
// 加锁,shutdown时会判断当前worker状态,根据独占锁是否空闲来判断当前worker是否在工作
w.lock();
/*
* (runStateAtLeast(ctl.get(), STOP) ||(Thread.interrupted() &&runStateAtLeast(ctl.get(), STOP))) &&!wt.isInterrupted()
* 1. 如果线程池状态大于等于stop那么去重置线程中断标记,如果已经是中断状态了则不设置
* 2. 如果线程打断标记是true并且状态大于等于stop那么也重置中断标记为true
*/
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
// 钩子方法
beforeExecute(wt, task);
// 如果thrown不为空那么task运行过程中抛出了异常
Throwable thrown = null;
try {
// 业务逻辑,可能是Runnable也可能是FutureTask
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 {
// help gc
task = null;
// 更新worker的完成任务数量
w.completedTasks++;
// 释放worker锁,正常情况会回到getTask方法获取任务,抛出异常直接去到finally
w.unlock();
}
}
// getTask方法返回null会来到这里,说明没任务了当前线程应该执行退出逻辑
completedAbruptly = false;
} finally {
// task.run内部抛出异常时执行
processWorkerExit(w, completedAbruptly);
}
}
2.方法变量说明
- wt: 当前线程
- task: worker的firstTask或是从getTask中获取的任务
- completedAbruptly: 线程运行任务的退出情况true为异常退出false为正常退出
- thrown: 线程运行任务,任务抛出的异常
3.情况说明
- 获取任务逻辑
- 如果有firstTask那先执行firstTask
- 没有firstTask调用getTask获取任务
- 中断逻辑
- 如果线程池状态大于等于stop那么会给当前线程一个中断信号
- 重置中断标记并且线程池状态大于等于stop也会给当前线程一个中断信号
- 运行任务逻辑
- worker加锁
- 检查是否要中断
- 钩子方法
- 运行任务的run方法
- 如果有异常那么捕捉异常并抛出
- 钩子方法
- 更新当前worker执行的任务数量
- worker解锁
- 没有任务或当前线程执行的任务出现了异常会走退出逻辑
核心方法getTask解析
1.源代码
private Runnable getTask() {
// 表示当前线程获取任务是否超时
boolean timedOut = false;
for (;;) {
// ctl
int c = ctl.get();
// 线程池状态
int rs = runStateOf(c);
/*
* 1. rs >= SHUTDOWN——条件成立说明当前线程池是非running状态
* 2. (rs >= STOP || workQueue.isEmpty()——如果线程池状态大于等于stop或阻塞队列为空
*/
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
// ctl-1
decrementWorkerCount();
return null;
}
// 线程池中线程的数量
int wc = workerCountOf(c);
/*
* 主要是为了实现超时机制(核心线程永远不会超时,救急线程会超时)
* allowCoreThreadTimeOut为true说明核心线程也可以回收也就是说核心线程也走超时逻辑
* keepAliveTime就是超时时间单位毫秒
* timed为ture说明当前线程获取任务有超时机制,反过来你懂的
* wc > corePoolSize说明当前线程是救急线程应该有超时机制
*/
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
/*
* 线程回收逻辑
* 1. (wc > maximumPoolSize || (timed && timedOut))——判断当前线程是否可以被回收
* 1.1:理论上来说是不应该成立但是setMaximumPoolSize可能成立,这个条件成立说明当前线程可以被回收
* 1.2:核心线程可以被回收并且这个线程上一次循环时使用poll方式获取任务超时了
* 2. (wc > 1 || workQueue.isEmpty())——回收条件
* 2.1:wc > 1——当前线程池的线程数量最小是2说明回收了当前线程还有其他线程不至于没线程了
* 2.2:workQueue.isEmpty()——如果队列是空当前线程可以被回收
*/
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
// 使用CAS机制把ctl值-1
if (compareAndDecrementWorkerCount(c))
return null;
// 如果当前线程退出失败那么自旋重新来过
continue;
}
try {
// 如果当前线程获取任务可以超时那么使用pool方式反过来使用take方式
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
// 获取成功退出
if (r != null)
return r;
// 超时了设置 timedOut=true
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
2.方法变量说明
- timedOut: 表示当前线程获取任务是否超时
- c: ctl
- rs: 线程池状态
- wc: 线程池中的线程数量
- timed: 当前线程获取任务是否支持超时
- r: 要返回的Runnable对象
3.情况说明
- 返回null的情况(返回null会在runWorker方法执行线程退出逻辑)
- 线程池状态大于等于stop
- 线程池状态为shutdown并且阻塞队列为空
- 当前线程是在最大线程数之外的线程并且当前线程不是最后一个线程
- 当前线程支持超时并且上一次获取任务的时候超时了 并且 阻塞队列是空的
- 从阻塞队列中获取任务并返回
核心方法processWorkerExit解析
1.源代码
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// 如果当前线程执行任务时异常退出的那么去维护下ctl
if (completedAbruptly)
decrementWorkerCount();
// 全局锁,因为要减少线程了
final ReentrantLock mainLock = this.mainLock;
// 加锁
mainLock.lock();
try {
// 当前线程完成的任务数量汇总到总数上
completedTaskCount += w.completedTasks;
// 把当前线程从池子中移除
workers.remove(w);
} finally {
// 解锁
mainLock.unlock();
}
tryTerminate();
// 获取ctl
int c = ctl.get();
// 当前线程池状态时running或shutdown
if (runStateLessThan(c, STOP)) {
// 当前线程是正常退出
if (!completedAbruptly) {
// 当前线程池最少线程数量
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
// 如果最少线程数量是0并且阻塞队列不是null说明阻塞队列还有任务最少要留一个线程
if (min == 0 && ! workQueue.isEmpty())
min = 1;
// 条件成立:说明线程池中的线程数量还大于最小线程数量不必增加线程直接return即可
if (workerCountOf(c) >= min)
return;
}
/*
* 走到这里会因为两种情况
* 1. 当前线程非正常退出,所以要创建一个新的线程顶上去
* 2. 当前线程数量小于最小线程数,要保证至少有一个线程
* 3. 当前线程数量小于核心线程数量,要保证核心线程数量为corePoolSize个
*/
addWorker(null, false);
}
}
2.方法说明
线程退出
3.方法入参说明
- w: 当前worker
- completedAbruptly: false代表线程正常退出,true代表异常退出
4.方法变量说明
- mainLock: 全局锁
- c: ctl
- min: 当前线程池最少线程数量
5.逻辑说明
- 维护workerCount
- 维护完成任务总数
- 把线程从池子中移除
- 保底逻辑(必须是running或shutdown状态)
- 不正常退出的线程在新增一个线程补上
- 线程池线程数量小于最小线程数量或核心线程数量
核心方法shutdown解析
1.源代码
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
// 获取全局锁
mainLock.lock();
try {
// 权限判断
checkShutdownAccess();
// 设置线程池状态为shutdown
advanceRunState(SHUTDOWN);
// 中断所有空闲线程
interruptIdleWorkers();
// 钩子方法
onShutdown();
} finally {
// 释放锁
mainLock.unlock();
}
tryTerminate();
}
2.方法说明
shutdown线程池
核心方法shutdownNow解析
1.源代码
public List<Runnable> shutdownNow() {
// 所有未处理的任务
List<Runnable> tasks;
// 全局锁
final ReentrantLock mainLock = this.mainLock;
// 加锁
mainLock.lock();
try {
// 权限判断
checkShutdownAccess();
// 设置线程池状态为sotp
advanceRunState(STOP);
// 中断线程池中所有线程(启动的没有被中断的线程才会收到这个状态)
interruptWorkers();
// 导出未处理的任务
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
2.方法说明
shutdownNow线程池
核心方法tryTerminate解析
1.源代码
final void tryTerminate() {
// 自旋
for (;;) {
// 获取ctl
int c = ctl.get();
/*
* 1. isRunning(c)——线程池是running状态
* 2. runStateAtLeast(c, TIDYING)——线程池状态已经是TIDYING状态了
* 3. (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())——shutdown状态并且队列不是null
*/
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
// 来到这里的情况:线程池状态>=stop并且不是TIDYING,线程池状态shutdown并且阻塞队列为空
// 当前线程池线程数量不是0
// 总结:唤醒所有空闲线程让他们退出,工作线程在执行完任务后也会自己退出
if (workerCountOf(c) != 0) {
// 中断1个线程(queue.take或queue.poll),唤醒后的方法会在getTask方法返回null执行退出逻辑的时候会再次调用这个方法然后唤醒下一个空闲线程
interruptIdleWorkers(ONLY_ONE);
return;
}
// 走到这里说明这是最后一个退出的线程
final ReentrantLock mainLock = this.mainLock;
// 全局锁加锁
mainLock.lock();
try {
// 重置线程池状态为TIDYING并且线程数量是0
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
// 空方法留下扩展的
terminated();
} finally {
// 重置线程池状态为TERMINATED并且线程数量是0
ctl.set(ctlOf(TERMINATED, 0));
// 唤醒所有调用了termination.awaitTermination的线程
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
}
}
2.方法说明
尝试退出线程池
3.逻辑总结
- 检查当前线程池状态是否可以退出
- 不是最后一个线程的退出逻辑
- 正在工作线程——执行结束后最终调用addWroker但是会因为状态不对无法添加而结束
- 阻塞线程——唤醒阻塞线程让阻塞线程执行退出逻辑并唤醒下一个阻塞线程以此类推
- 最后一个退出线程
- 设置线程池状态
- 唤醒等待线程