在分析ThreadPoolExecutor线程池之前, 需要先对对线程池的状态与线程的数量进行了解
// 记录线程池状态和线程数量(总共32位,前3位表示线程池状态,后29位表示线程数量)
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 线程数量统计位数29 Integer.SIZE=32
private static final int COUNT_BITS = Integer.SIZE - 3;
/*
容量:
1的二进制: 0000 0000 0000 0000 0000 0000 0000 0001
向左移动29位: 0010 0000 0000 0000 0000 0000 0000 0000
减1等到: 0001 1111 1111 1111 1111 1111 1111 1111
*/
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
/*
运行状态:
-1的二进制: 1000 0000 0000 0000 0000 0000 0000 0001
反码: 0111 1111 1111 1111 1111 1111 1111 1110
补码: 0111 1111 1111 1111 1111 1111 1111 1111
向左移动29位: 1110 0000 0000 0000 0000 0000 0001
*/
private static final int RUNNING = -1 << COUNT_BITS;
/*
关闭状态: 拒绝新任务但是处理阻塞队列里的任务
0的二进制: 0000 0000 0000 0000 0000 0000 0000 0000
向左移动29位: 0000 0000 0000 0000 0000 0000 0000
*/
private static final int SHUTDOWN = 0 << COUNT_BITS;
/*
停止状态: 拒绝新任务并且抛弃阻塞队列里的任务同时会中断正在处理的任务
0的二进制: 0000 0000 0000 0000 0000 0000 0000 0001
向左移动29位: 0010 0000 0000 0000 0000 0000 0000
*/
private static final int STOP = 1 << COUNT_BITS;
/*
整理状态: 所有任务都执行完(包含阻塞队列里面任务)当前线程池活动,线程为0,将要调用terminated方法
0的二进制: 0000 0000 0000 0000 0000 0000 0000 0010
向左移动29位: 0100 0000 0000 0000 0000 0000 0000
*/
private static final int TIDYING = 2 << COUNT_BITS;
/*
终止状态: terminated方法调用完成以后的状态法
0的二进制: 0000 0000 0000 0000 0000 0000 0000 0011
向左移动29位: 0110 0000 0000 0000 0000 0000 0000
*/
private static final int TERMINATED = 3 << COUNT_BITS;
// 获取运行状态(获取前3位)
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 获取线程个数(获取后29位)
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
//用于存放线程任务的阻塞队列
private final BlockingQueue workQueue;
//重入锁
private final ReentrantLock mainLock = new ReentrantLock();
//线程池当中的线程集合,只有当拥有mainLock锁的时候,才可以进行访问
private final HashSet workers = new HashSet();
//等待条件支持终止
private final Condition termination = mainLock.newCondition();
//创建新线程的线程工厂
private volatile ThreadFactory threadFactory;
//饱和策略
private volatile RejectedExecutionHandler handler;
二进制位运算总结
正数的原码、反码、补码都一样;
负数的反码 = 原码的符号位不变,其他位取反;
负数的补码 = 反码+1;
0的原码、反码、补码都是0;
计算机以补码进行运算;
取反不同于反码;
线程池创建时, 线程的状态为运作中, 线程的数量为0
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
我们先来分析一下execute 操作
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
// 获取线程池状态和线程数量
int c = ctl.get();
// 判断线程个数与核心线程数 ,小于这执行addWorker(com, true)方法
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 如果线程池处于RUNNING状态,则添加任务到阻塞队列
if (isRunning(c) && workQueue.offer(command)) {
// 二次检查
int recheck = ctl.get();
// 如果线程池不处于RUNNING状态 , 从队列中删除
if (! isRunning(recheck) && remove(command))
//执行处理策略
reject(command);
// 如果当前线程池数量为空, 执行addWorker(null, false)方法
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 执行addWorker(com, false)
else if (!addWorker(command, false))
reject(command);
}
看完上面源码,其中有三个地方执行了 addWorker 方法, 且参数不一样, 下面对addWorker源码分析
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
// 获状线程状态
int rs = runStateOf(c);
// 线程不处于运行中 && ! (关闭 && 任务为空 && 队列不为空)返回false
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
// 线程运行 或者 线程关闭任务不为空或者队列不为空往下运行
for (;;) {
// 获取线程个数
int wc = workerCountOf(c);
// 线程数大于容量数 || 线程数大于核心/最大线程数, 返回false
if (wc >= CAPACITY ||
// core如果为true, 线程数与线程池核心线程数比较,false, 线程数与线程池最大线程数比较
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 比较与替换线程数 + 1, 成功->循环, 失败->重新执行这个循环
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 创建Worker, 后面分析
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());
// 线程运行中 || (线程关闭 && 任务为空)
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 若创建的Thread是活动的抛异常
if (t.isAlive())
throw new IllegalThreadStateException();
// 下面的操作是将Worker加入列表中, 执行, 执行完毕删除
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
// 线程启动,执行任务(Worker.thread(firstTask).start())
// 找到Worker的实现的run方法
t.start();
workerStarted = true;
}
}
} finally {
// 若执行失败, 清理工作
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
addWorker方法可以拆分为两个阶段
阶段一: 使用循环 + CAS增加线程数
阶段二: 加锁,创建Worker,然后执行任务
下面分析Worker对象
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
private static final long serialVersionUID = 6138294804551838833L;
// 线程工厂生成的线程, 创建ThreadPoolExecutor指定工厂
final Thread thread;
// 要运行的初始任务
Runnable firstTask;
// 统计执行了多少个线程
volatile long completedTasks;
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
addWorder方法中执行 t.start();方法, 实际是在运行Worder中的run方法
public void run() {
runWorker(this);
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // 释放锁, 允许中断
boolean completedAbruptly = true;
try {
// 先执行firstTask,再从workerQueue中取task(getTask()),一直循环执行
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
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;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
// 处理并退出当前worker
processWorkerExit(w, completedAbruptly);
}
}
runWorker主要分为几步
- 拿到任务 : getTask
- 加锁执行任务
- 执行完毕之后做善后工作 : processWorkerExit
getTask方法
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// 此处决定是否销毁线程, 条件是开启了 allowCoreThreadTimeOut,或者总线程数大于了核心线程数
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
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;
}
}
}
如果设置了allowCoreThreadTimeOut(true) 或者当前运行的任务数大于设置的核心线程数,那么timed =true .此时将使用workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)从任务队列中取任务,而如果没有设置,那么使用workQueue.take() 取任务,对于阻塞队列,poll(long timeout, TimeUnit unit) 将会在规定的时间内去任务, 如果没取到就返回null, take()会一直阻塞,等待任务的添加. 这里就是为什么核心线程数可以一直存在, 不被销毁的原因
processWorkerExit 方法
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // 如果是突然完成,需要通过CAS操作,workerCount-1
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 线程池统计的完成任务数completedTaskCount加上worker当中完成的任务数
completedTaskCount += w.completedTasks;
workers.remove(w);// 从线程集合移除
} finally {
mainLock.unlock();
}
// 尝试终止线程池
tryTerminate();
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
addWorker(null, false);
}
}
小结
线程池源码分析的时候, 需要围绕这execute的执行流程阅读, 然后理解ThreadPoolExecutor七大参数在代码中的作用:
- corePoolSize: 线程池中的核心线程数
1.1 判断线程数是否小于核心线程数, 小于则直接创建创建线程并执行工作
1.2 若线程数小于核心线程数, workQueue.take(), 阻塞, 保证核心线程数一直存活 - maximumPoolSize: 最大线程数, 必须大于1
2.1 判断线程数是否大于最大线程数, 大于则执行拒绝策略 - keepAliveTime: 多余的空闲时间
3.1 若线程数大于核心线程数, workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS), 超时将多余的线程回收 - unit: keepAliveTime单位
4.1 多余时间单位 - queueCapacity: 任务队列
5.1 任务队列若满, 创建线程去执行任务, 所以需要注意, 队列长度不能设置太长, 若设置太长, 无法创建新的线程执行任务
5.2 使用阻塞队列的特性, 保证核心线程的存活与多余线程的超时回收 - threadFactory: 线程池中线程工厂
6.1 创建Worker中的Thread的线程工厂, 在开发工厂中, 可以设置为带模块的名字, 方便线程追踪 - rejectedExecutionHandler: 拒绝策略