重要变量介绍
//首先要知道一点,线程池状态跟线程池线程数量由一个整数控制,二进制标识,高三位是
//表示状态,底29位表示线程数量
// ctl 原子操作 ,表示线程池状态+线程池数量
//ctlOf(RUNNING, 0) 初始值,线程数量为0,线程池状态 运行中
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//32-3=29 表示低位29是线程池线程数量
private static final int COUNT_BITS = Integer.SIZE - 3;
//1左移29位 然后减1
//从29位开始都是1
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// -1左移29位 高三位都是1,低29位都是0 表示线程池状态运行中
private static final int RUNNING = -1 << COUNT_BITS;
// 0 左移 19 32位都是0 调用 shutdown()方法之后
//表示线程池即将关闭,不接受新任务,但是会执行剩余任务
private static final int SHUTDOWN = 0 << COUNT_BITS;
//1左移29位 001 00000000000000000000000000000
//表示线程池 关闭了,调用shutdownnow()方法的时候,状态转变
//不接受新任务,停止正在执行的任务
private static final int STOP = 1 << COUNT_BITS;
//2左移29位置 010 00000000000000000000000000000
//线程池即将关闭,任务都执行完或者都停止了,没有需要执行的任务也灭有正在执行的任务
private static final int TIDYING = 2 << COUNT_BITS;
///3左移29位置 011 00000000000000000000000000000
//当线程池状态为 TIDYING 然后执行了 terminated() 钩子方法之后,状态变为 TERMINATED
//这个应该是终态了
private static final int TERMINATED = 3 << COUNT_BITS;
//CAPACITY 取反 & c(c是ctl.get()出来的结果,也就是线程数量+线程池状态)
//CAPACITY 取反 得到高位3位都是1 低29位都是0
//c & 上 CAPACITY 取反 得到 c 高3位的值,其实就是得到线程池状态
private static int runStateOf(int c) { return c & ~CAPACITY; }
//类似 runStateOf 得到 c 低29位值,也就是线程池数量
private static int workerCountOf(int c) { return c & CAPACITY; }
//线程池数量+线程池状态
private static int ctlOf(int rs, int wc) { return rs | wc; }
上面介绍的是线程池数量跟状态的表示,32位二进制,高三位表示线程池状态,低29位表示线程池线程数量。
线程池状态变化
RUNNING->SHUTDOWN:运行中,调用shutdown方法,开始停止接受新任务,把线程池中的所有任务执行完。
RUNNING->STOP:运行中,调用shutdownnow方法,停止接受新任务,清空任务队列,停止正在执行的任务,所以 shutdown 跟 shutdownnow 不一样的就是 shutdownnow,会清空队列,而且停止正在执行的任务
SHUTDOWN->STOP:任务清空了
构造方法
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;
}
1.corePoolSize:核心线程数量
2.maximumPoolSize:最大线程数量
3.keepAliveTime: 超过最大线程数量,线程存活时间
4.unit:搭配 keepAliveTime 表示单位
5.workQueue:阻塞队列,一般有 ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue
6.handler:拒绝策略
7.threadFactory :线程生成工厂
worker
故名思意就是打工人,负责执行任务的类,其实也就是线程
//继承 aqs ,可以当作一把锁
//失效 runable 有run方法,可以当作线程执行任务
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
//当前线程
final Thread thread;
//第一个任务,这个解释下,这个有两种情况
//1.新建worker的时候传入一个task任务,让woker执行,firsttask 不为空
//2.firsttask 为空,需要不断从队列中获取任务执行
Runnable firstTask;
//这个线程完成的任务数量
volatile long completedTasks;
// 构造方法,设置 firsttask 跟 调用线程工厂创建一个新线程
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
//run方法 真正干活的地方
public void run() {
runWorker(this);
}
execute 方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
// c:线程池数量+线程池状态
int c = ctl.get();
//如果目前线程池的线程数量 小于 核心线程数量 增加任务
if (workerCountOf(c) < corePoolSize) {
//增加任务,如果添加任务成功就返回
if (addWorker(command, true))
return;
//添加任务失败,可能存在并发,当前线程数量已经大于核心线程
//重新获取 c 走下面逻辑
c = ctl.get();
}
//添加核心线程失败或者当前线程数量大于核心线程数量
//判断当前线程状态是否 在运行中,如果在运行中 就把任务放到队列中
//这边写的蛮巧妙的,在开发中好像都没这么写过,if中如果 isRuning 为ture
//就执行 workqueue.offer
if (isRunning(c) && workQueue.offer(command)) {
//添加队列成功之后,再次检查线程池状态
int recheck = ctl.get();
//如果线程池不为运行中,就移除刚才放入列队的任务
//如果不为运行中,就不接受新任务了,所以移除
if (! isRunning(recheck) && remove(command))
//移除成功,执行拒绝策略
reject(command);
//如果线程运行中,而且当前线程数量为0,就增加新任务
//为什么要增加这一步,可能核心线程为0,添加任务到队列之后
//线程为0了,这时候就没有线程去轮询到队列拿任务来执行,所以要新建woker
//这边的addwokrer 要注意跟上面的 addworker 不一样
//第一个入参是任务为空,因为新加woker 要从队列拿,所以为空
//第二个参数false ,表示是否核心线程,这边因为第一个if没走到,所以不是核心线程
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//走到这里,说明添加任务到队列失败了,也就是队列满了,队列满了,就增加任务
//注意第二个参数false,表示非核心线程
else if (!addWorker(command, false))
//如果添加任务失败,执行拒绝策略
reject(command);
}
从上面三个if可以大概看出添加线程到线程池的流程:1、线程池数量小于核心线程:新增线程。 2、线程池数量不小于核心线程,也就是核心线程满了,把任务放放到任务队列 3、任务队列满了,新增线程为非核心线程,新增失败,也就是最大线程满了,执行拒绝策略。 说到执行拒绝策略,这边可以看到有两个地方调用 1、核心线程满了,放到队列成功,但是线程池状态不是运行中 2、最大线程满了,也执行拒绝策略
addWorker
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
//第一层for循环
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 这是一个校验,校验不过就返回false 表示添加任务失败。什么时候校验不过
//1. rs >= SHUTDOWN : 除了runing rs 都是大于等于 shutdown,也就是非runing
//2.满足下面其中一个条件就行
//2.1 rs不是shutdown,如果不是 shutdown ,那就是大于 shutdown,说明此时
//线程不能再接受新任务,不执行现有任务,所以返回false没问题
//2.2 firsttask != null 说明此时是shutdown,但是是新增任务,如果是shutdown
//就不新增任务了,而firsttask不为空,表示新增任务,所以返回false表示不接受
//2.3 workqueue 是空队列,说明此时是shutdown,firsttask 为空,不是新增任务
//那就是要从队列中执行任务,但是队列为空,所以返回false
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
//上面校验成功,这是第二层for循环
for (;;) {
int wc = workerCountOf(c);
//如果工作线程大于线程最大数量 或者 线程数量大于核心数量/最大数量
//这个根据传入的参数 core 判断此时是要创建核心线程还是非核心线程
//就返回false 表示新增线程失败
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//如果新增线程数量允许,那就cas新增工作线程数量
if (compareAndIncrementWorkerCount(c))
//cas成功,就退出两层for循环,到真的新增worker的逻辑
break retry;
//cas失败,表示有并发
c = ctl.get(); // Re-read ctl
//检查线程状态是否变化,如果变化了,跳到第一次线程再次检查线程状态
//如果线程状态没有变化,那就是工作线程数量变化了,第二次循环再来一次cas
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//new 一个工作线程
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
//全局锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
.
int rs = runStateOf(ctl.get());
//rs < SHUTDOWN 表示 线程正常运行
//rs == SHUTDOWN && firstTask == null
//表示线程虽然 shutdown 但是firsttask为空,可以从队列拿任务来执行
//以上两种情况都可以执行任务
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive())
throw new IllegalThreadStateException();
//往线程list添加线程
workers.add(w);
//当前线程的大小
int s = workers.size();
//largestPoolSize 表示该线程出现过最大的线程数量
//因为线程池线程数量一直变化,这个是再记录,具体用处不知道
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
//全局锁解锁
mainLock.unlock();
}
if (workerAdded) {
//开始线程,执行任务,后续流程看这个
t.start();
workerStarted = true;
}
}
} finally {
//添加任务失败,需要把线程数量啥的减一
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
addworker这个方法首先有两个for循环。第一个循环:校验线程池状态是否正常,如果不正常就返回fasle,表示执行失败 第二个循环:校验线程数数量是否正常,如果正常cas修改线程池数量,cas失败则还有两种情况,第一种状态变化了,第二种数量变化了。所以两层循环一个目的是校验,另一个目的是cas修改线程数量。执行完循环之后,真的开始创建线程,开启线程,然后最后再finally 中 判断如果新增线程失败,通过 addWorkerFailed 来处理
addWorkerFailed
//添加任务失败后需要处理的
private void addWorkerFailed(Worker w) {
//全局锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//如果任务不为空,往任务列表移除任务
if (w != null)
workers.remove(w);
//最开始有cas新增线程数量,线程cas减少线程数量
decrementWorkerCount();
//因为新增任务失败,尝试 terminate 线程池,这个后面说
tryTerminate();
} finally {
mainLock.unlock();
}
}
runworker
//上面添加完线程之后,start线程,然后到run方法,run方法执行 runworker方法
//也就是线程真正干活的地方
final void runWorker(Worker w) {
//当前线程
Thread wt = Thread.currentThread();
//第一个任务,可能为空,为空就从队列取
Runnable task = w.firstTask;
//把当前第一个任务值为空
w.firstTask = null;
//这个不是全局锁了,是当前线程一个锁,不知道为啥一来就 unlock
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//while循环,两个情况,第一个i情况,当前worker 有第一个任务,直接执行
//第二个情况,从队列拿任务,任务不为空,拿任务来执行
while (task != null || (task = getTask()) != null) {
//进入就锁住,己住这个
w.lock();
// 如果线程池状态大于等stop,说明此时不能执行任务了
//而且当前线程没有中断,满足这两个条件,线程中断
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
//上面的校验主要是,预防再执行任务的时候判断线程是否被中断了,比如说
//shutdownnow 就会中断线程
//钩子方法
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为空,方便下次循环来队列拿任务
task = null;
//该线程执行的任务++
w.completedTasks++;
//解锁
w.unlock();
}
}
//什么时候 这个会是false ,当获取任务为空的时候这个会是false
//当发生异常的时候 就走不到这里 这个值就是 true
completedAbruptly = false;
} finally {
//说明这个线程结束了,线程结束需要处理一些逻辑
//completedAbruptly 通过这个字段可以看出,线程为什么结束
//1.队列拿不到任务(false) 2.发生异常 (true)
processWorkerExit(w, completedAbruptly);
}
}
runWorker 主要是再线程中不停的循环拿任务执行,拿不到任务 getTask(),线程执行完毕,调用 processWorkerExit 方法
getTask
//这是线程从队列拿任务
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
//for 循环拿任务
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 什么情况下不能拿任务了
//1.线程池状态 大于 shutdown 2.队列为空
//要注意 线程池状态 等于 shutdown 的时候还可以从队列拿任务来执行,知道队列为空
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
//不能再拿任务了,需要关闭线程了,线程池数量减一,返回空,线程执行完毕
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
//allowCoreThreadTimeOut 这个字段如果设置为 true 表示核心线程允许回收
// time 为 ture ,要么是 allowCoreThreadTimeOut = true ,要么此时 线程池
//数量大于核心线程
//这个字段是干嘛的?判断拿拿任务需不需设置超时时间
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//如果线程大于最大线程数量 或者 超时了而且允许设置超时
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
//减少工作线程,返回空
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
//是否需要超时控制,如果需要就用poll 超时返回null
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
processWorkerExit
//线程退出后需要执行的操作
private void processWorkerExit(Worker w, boolean completedAbruptly) {
//completedAbruptly = true 说明发生异常了
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
//所以需要减少线程数量,不然再gettask 方法就会减少线程数量
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//全局的线程完成任务统计
completedTaskCount += w.completedTasks;
//移除线程
workers.remove(w);
} finally {
mainLock.unlock();
}
tryTerminate();
int c = ctl.get();
//当前状态小于 stop 也就是 runing 或者 shutdown
if (runStateLessThan(c, STOP)) {
//completedAbruptly = false 说明获取任务为空
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
//如果获取任务为空,那就是正常退出的,如果当前线程数量大于等于最小值
//那就不需要重新新建线程了
if (workerCountOf(c) >= min)
return; // replacement not needed
}
//添加新线程
//1.发生异常,会新建线程执行任务
//2.获取任务为空,但是当前线程数量小于最小值,就新建线程
addWorker(null, false);
}
}