1 ThreadPoolExecutor介绍
ThreadPoolExecutor是线程池是实现。包含了对线程生命周期的管理。ThreadPoolExecutor的核心参数包括:
//线程工厂,设置线程名字,方便定位线程
private volatile ThreadFactory threadFactory;
//超过最大线程数量之后执行的饱和策略
1.AbortPolicy:直接抛出异常。 2.CallerRunsPolicy:只用调用者所在线程来运行任务。
3.DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
4.DiscardPolicy:不处理,丢弃掉。
5.也可以根据自定义策略。如先持久化,记录日志或者数据库,后续补偿。
private volatile RejectedExecutionHandler handler;
//线程空闲时间,超过这个时间,线程自动退出(默认针对超出corePoolSize的线程)
private volatile long keepAliveTime;
//是否回收核心线程
private volatile boolean allowCoreThreadTimeOut;
//核心线程数量:
//小于该数量,执行任务时会创建新的线程
//默认核心线程是不会回收的,当然也可以设置成可回收
private volatile int corePoolSize;
//最大线程数量(包括线程队列里面的线程数量),达到这个线程数的时候会执行饱和策略
private volatile int maximumPoolSize;
//线程任务队列
1.ArrayBlockingQueue:基于数组的有界阻塞队列,此队列有序: FIFO(先进先出)。
2.LinkedBlockingQueue:基于链表的阻塞队列,此队列有序: 吞吐量通常要高于ArrayBlockingQueue
3.SynchronousQueue:不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用取出操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue
4.PriorityBlockingQueue:具有优先级的无界阻塞队列。
private final BlockingQueue workQueue;
//默认饱和策略
private static final RejectedExecutionHandler defaultHandler =
new ThreadPoolExecutor.AbortPolicy();
注意:
threadFactory
一般自定义为线程池创建线程用,通常会为线程创建一个易于理解的名称。
allowCoreThreadTimeOut
默认是false
,当为true
是可以回收空闲的核心线程数。
handler
通常可以自定义拒绝策略,可以实现任务持久化,便于后期补偿。
2 ThreadPoolExecutor的状态
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//29
private static final int COUNT_BITS = Integer.SIZE - 3;
// 000-1111111111111111111111111
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// 111 - 0000000000000000000000000000(十进制: -536, 870, 912)
private static final int RUNNING = -1 << COUNT_BITS;
// 000 - 0000000000000000000000000(十进制: 0)
private static final int SHUTDOWN = 0 << COUNT_BITS;
// 001 - 00000000000000000000000000(十进制: 536,870, 912)
private static final int STOP = 1 << COUNT_BITS;
// 010 - 00000000000000000000000000.(十进制值: 1, 073, 741, 824)
private static final int TIDYING = 2 << COUNT_BITS;
// 011 - 000000000000000000000000000(十进制值: 1, 610,612, 736)
private static final int TERMINATED = 3 << COUNT_BITS;
ThreadPoolExecutor
通过ctl
保存线程池的状态和工作线程数,ctl
是一个32位整数,高3位表示线程池状态,低29位表示工作线程数量(workCount),所有工作线程的最大数量是2^29-1。
线程池的状态数值大小一次是RUNNING
<SHUTDOWN
<STOP
<TIDYING
<TERMINATED
,并且只有RUNNING
状态是负数,这样设计的原因是方便状态判断。
线程池状态分为5种:RUNNING
、SHUTDOWN
、STOP
、TIDYING
、TERMINATED
- RUNNING:(运行)接收新的任务并处理队列里的任务
- SHUTDOWN:(关闭)不接收新的任务,但是队列中任务会执行
- STOP:(停止)不接收新的任务,不处理队列中的任务,并终止正在处理的任务
- TIDYING:(整理)所有任务都被终止的,同时工作线程数量为0
- TERMINATED:(已终止) terminated()方法执行结束后会进入这一状态,表示线程池已关闭。terminated()方法默认是空方法,可以自定义实现。
下面是这五种状态的转换:
RUNNING -> SHUTDOWN:通过调用
shutdown()
方法实现。(RUNNING or SHUTDOWN) -> STOP:通过调用
shutdownNow()
方法实现。SHUTDOWN -> TIDYING:task队列和,worker集合为空。
STOP -> TIDYING:worker集合为空。
TIDYING -> TERMINATED:执行完
terminated()
方法后。
注意:
ThreadPoolExecutor
只提供了shutdown()
和shutdownNow()
两个方法转换状态。其他状态的转变都是隐式装换(tryTerminate()方法中完成)。但是可以通过如下方法查看线程池状态:
public boolean isTerminating() {
int c = ctl.get();
return ! isRunning(c) && runStateLessThan(c, TERMINATED);
}
public boolean isTerminated() {
return runStateAtLeast(ctl.get(), TERMINATED);
}
public boolean isShutdown() {
return ! isRunning(ctl.get());
}
2.1 ThreadPoolExecutor获取状态和线程数
//~CAPACITY: 11100000000000000000000000000001
//return c & ~CAPACITY:获取c高3位
private static int runStateOf(int c) { return c & ~CAPACITY; }
//CAPACITY:00011111111111111111111111111111
//c & CAPACITY:返回的就是c的低29位
private static int workerCountOf(int c) { return c & CAPACITY; }
//SHUTDOWN是0,小于SHUTDOWN,也就是判断是否是RUNNING
private static boolean isRunning(int c) { return c < SHUTDOWN;}
//通过状态和线程数量组合ctl
private static int ctlOf(int rs, int wc) { return rs | wc; }
2.2 线程池状态判断
// 判断当前线程池运行状态值是否小于给定值
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
// 判断当前线程池运行状态值是否大于等于给定值
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
3 ThreadPoolExecutor的运行过程
3.1 execute方法
public void execute(Runnable command) {
if (command == null)
//不能为null
throw new NullPointerException();
int c = ctl.get();
//返回ctl的低29位,判断是否小于核心线程数
if (workerCountOf(c) < corePoolSize) {
//创建核心线程执行任务
if (addWorker(command, true))
//成功就返回
return;
//失败重新获取ctl
c = ctl.get();
}
//走到这,说明大于核心线程数,则判断是否是运行状态,是就往队列中加任务
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
//如果不是RUNNING,就移除当前任务
if (! isRunning(recheck) && remove(command))
//失败就执行拒绝策略
reject(command);
//判断线程总数量是否为0(有可能线程执行任务报错了,然后就被销毁了)
else if (workerCountOf(recheck) == 0)
//创建非核心线程执行任务(注意这里是null)
addWorker(null, false);
}
//走到这,说明不是运行状态或者队列满了,就创建非核心线程执行任务
else if (!addWorker(command, false))
//失败就执行拒绝策略
reject(command);
}
上述代码的执行流程如下:
注意:
只有在线程池处于RUNNING
状态时提交任务的任务才会被执行,否则执行拒绝策略。
3.2 addWorker方法
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
// 运行状态
int rs = runStateOf(c);
// Check if queue empty only if necessary.
// 分两种情况考虑:
// 1、如果线程池状态>SHUTDOWN,即(STOP,TIDYING,TERMINATED)中的一个,直接返回false(因为这些条件下要求 清空队列,正在运行的任务也要停止)
// 2、如果线程池状态=SHUTDOWN & (firstTask!=null || 队列为空)直接返回false,
// 换言之,在SHUTDOWN状态下, 想要创建一个firstTask为空的新worker,需要确保队列不为空(队列为空就意味着这个新的worker暂时还没有任务可以执行,所以也没有创建worker的必要, 因为这个worker是用来消化队列中的任务)
// 大部分情况下,我们需要新创建的worker的firstTask都有初始化任务, 在SHUTDOWN状态下,就不允许在创建worker了,直接返回false
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
// 计算worker的数量
int wc = workerCountOf(c);
// 如果worker数量已经超过指定大小,则不允许创建
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 尝试cas累加worker的数量,如果成功就跳出最外层循环
if (compareAndIncrementWorkerCount(c))
break retry;
// 本次cas失败,表明ctl已经变了,检查线程池状态,如果状态变了就跳到最外层重新执行一次
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
// 如果到这里了说明是worker的数量改变了导致的cas失败,那就在内层自旋操作 再来一次
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
// 状态rs < SHUTDOWN表明是RUNNING状态
// 如果线程池的状态是SHUTDOWN,那么创建的worker是用来处理队列中的任务,因此需要满足firstTask == null
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 如果线程提前start则认为是异常状态
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
// 就是记录一下线程池在运行中线程数量的最大值
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
// 这里启动worker运行
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
// 如果添加worker失败了,这里需要处理一下
addWorkerFailed(w);
}
return workerStarted;
}
当创建新worker时,firstTask为null的含义:
首先需要知道的是worker执行的任务的来源,一是初始化时的firstTask 即当前worker的第一个任务, 二是从队列里取
firstTask表示当前worker初始化任务,也就是第一个要执行的任务;如果firstTask=null, 说明此worker只从队列中取任务来执行
所以当创建firstTask为null的worker时,只有队列不为空才有创建的必要,因为目的是去消化队列中的任务
分三种情况来看创建worker:
正常情况下线程池的状态是RUNNING,这个时候只需根据corePoolSize或者maximumPoolSize来判断是否应该创建新的woker
如果是STOP,TIDYING,TERMINATED状态,表明线程池处于清理资源,关闭线程池(清空队列,终止正在运行的任务,清空worker),这个时候不允许创建新的worker
SHUTDOWN状态,此状态比较特殊,因为在此状态会继续处理队列中的任务,但是不允许往队列中新增任务,同时正常处理的任务也会继续处理; 此状态下,在firstTask为null并且队列不为空的情况下可以创建新的worker来处理队列中的任务,其他情况是不允许的
3.3 addWorkerFailed方法
当worker启动失败时处理:
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
workers.remove(w);
// worker计数器减1
decrementWorkerCount();
// 尝试终止线程池
tryTerminate();
} finally {
mainLock.unlock();
}
}
4 Worker线程
worker继承AbstractQueuedSynchronizer,实现了非重入锁
- state=0, 表示锁未被持有
- state=1, 表示锁被持有
- state=-1, 初始化的值,防止worker线程在真正运行task之前被中断,
Worker也是一个任务,实现了Runnable接口。
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
// 每个worker中都会封装一个真正用于处理任务的线程
final Thread thread;
// 这个worker初始化的时候分配的首个任务
Runnable firstTask;
// 记录当前worker处理完的任务数量
volatile long completedTasks;
// 构造方法
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
// 使用ThreadFactory创建线程
// 这里this是当前实现了Runnable接口的Worker对象,也就是说当我调用thread.start()方法时,就会调用worker的入口方法run
this.thread = getThreadFactory().newThread(this);
}
// 基于AQS实现的非重入锁
protected boolean isHeldExclusively() {
return getState() != 0;
}
// 实际并未使用传入的参数
// state=0表示可以获取,将state设置为1表示获取成功
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// 实际并未使用传入的参数
// 将state设置为0表示锁释放成功
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(); }
// worker的主要入口逻辑
public void run() {
runWorker(this);
}
}
4.1 runWorker方法
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
// 和setState(-1); 相对应
// 这个时候state=0了,也就可以被中断了,(ThreadPoolExecutor.Worker#interruptIfStarted)
w.unlock(); // allow interrupts
// 是否有异常产生
boolean completedAbruptly = true;
try {
// task的来源要么是firstTask,要么是队列
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
// 如果线程池是STOP及之后的状态,需要确保它是中断的
// 如果是STOP之前的状态,就要确保它不能被中断(如果有的话就要清除中断标志,Thread.interrupted会清除中断标志)
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);
}
}
注意:
Worker有两种方式结束线程执行:
task.run()
执行业务方法时抛出异常,或者响应wt.interrupt()
中断抛出异常。getTask()
方法返回null,正常退出执行。
线程退出时会执行processWorkerExit()
方法,completedAbruptly
为true
表示异常退出,false
表示正常退出。
Worker线程通过加锁改变state状态来表示线程是否空闲。beforeExecute
和afterExecute
可以自定义实现扩展。
4.2 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.
// 两种情况从队列里面取不到task
// 1、线程池是STOP状态,这个状态会清空队列,同时停止正在处理的任务,自然,如果是这个状态,直接返回null,表明取不到task
// 2、线程池是SHUTDOWN状态并且队列为空,因为此状态下 队列里是不会新增任何task,所以在队列为空的情况下,自然也是取不到
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
// worker数量减一
decrementWorkerCount();
return null;
}
// 计算worker数量
int wc = workerCountOf(c);
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 通过最大线程数量或者获取task超时 来决定是否要消减此worker
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 1、timed期限的,非核心线程如果空闲时间超过keepAliveTime,就会被清理掉
// 因此如果这里从阻塞队列里在keepAliveTime时间内都没有取到task,说明处理超时了
// 2、没有timed限制的,take阻塞的取task
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
此方法有两处返回null,用于退出线程。
第一处:
当线程池处于STOP及之后的状态
线程池处于SHUTDOWN状态并且任务队列没有任务。
第二处:
线程数超过最大线程数
线程获取任务超时
注意:
此方法是用于清除空闲线程,通过超时获取任务队列来清除非核心线程,通过设置allowCoreThreadTimeOut
为true
也可以清除空闲的核心线程。
4.3 processWorkerExit方法
对worker执行结束之后,清理掉当前worker之后考虑是否采取用新的worker来替换
private void processWorkerExit(Worker w, boolean completedAbruptly) {
//异常结束workerCount减一,正常结束在getTask已经
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 当前worker完成的task数量累加
completedTaskCount += w.completedTasks;
// 从woker Set中移除当前worker
workers.remove(w);
} finally {
mainLock.unlock();
}
// 每次worker结束后都要尝试终止线程池,说不定某个时刻worker都被清理了并且达到了线程池终止的条件
// 就可以从这里结束
tryTerminate();
int c = ctl.get();
// 如果线程池状态小于STOP
if (runStateLessThan(c, STOP)) {
// 如果不是异常
// 如果用户任务发生了异常,尝试替换worker
// 或者核心线程数量小于corePoolSize,尝试添加worker
// 或者队列非空,但是已经没有worker了,尝试添加worker
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
// 这里新添加worker,没有初始化的firstTask, 这里worker处理的任务来自于队列
addWorker(null, false);
}
}
流程说明:
从worker set中移除当前worker
尝试终止线程池
-
如果线程池状态还未达到STOP,则可以根据以下情况添加新的worker
用户task抛出了异常(也就是completedAbruptly=true)
运行的线程数已经小于核心线程数
运行的线程数为0,但是队列中的任务不为空
5 线程池关闭
5.1 shutDown方法
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 如果有security管理,需要确保有权限去shutdown线程池
checkShutdownAccess();
// 设置线程池状态为SHUTDOWN
advanceRunState(SHUTDOWN);
// 中断所有空闲线程
interruptIdleWorkers();
// 为ScheduledThreadPoolExecutor提供的钩子方法
onShutdown(); // hook for ScheduledThreadPoolExecutor
} 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的锁资源肯定是可以直接获取到的,因此根据此便可以判别线程是否空闲
if (!t.isInterrupted() && w.tryLock()) {
try {
// 打上中断标志
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
流程说明:
- 先将线程池的状态改为SHUTDOWN
- 尝试中断所有空闲线程(通过线程是否可加锁判断是否空闲)
- 尝试终止线程池
5.2 shutDownNow方法
// 返回队列中未执行的task列表
public List shutdownNow() {
List tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
// 将线池的状态设置为STOP
advanceRunState(STOP);
// 中断所有worker
interruptWorkers();
// 清空队列
tasks = drainQueue();
} finally {
mainLock.unlock();
}
// 尝试终止线程池
// 虽然线程池状态已经改成了STOP状态,但还需要workers被清空之后才会真正变成TERMINATED状态
// 所以这里不一定会成功, runWorker方法中处理worker退出时会触发tryTerminate
tryTerminate();
return tasks;
}
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
// Worker内部方法
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
流程说明:
先将线程池的状态改为STOP
尝试中断所有线程
清空任务队列
尝试终止线程池
5.3 tryTerminate方法
尝试关闭线程池
final void tryTerminate() {
for (;;) {
int c = ctl.get();
// 如果线程池是RUNNING状态的
// 如果线程池是TIDYING、TERMINATED状态的不管(基本已经处于关闭状态了)
// 如果线程池是SHUTDOWN状态并且队列中还有task(SHUTDOWN态下还是会处理现有的task)
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
// 到这里就说明需要开始线程池终止操作
if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 操作1:设置线程池状态为TIDYING,worker数量为0
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
// terminated钩子方法
terminated();
} finally {
// 操作1设置后,又处理了terminated方法,那么就可以把线程池置为TERMINATED状态了(线程池已完全关闭)
ctl.set(ctlOf(TERMINATED, 0));
// 通知在termination条件上等待的操作
// 比如awaitTermination方法的等待操作,这里唤醒后,可能会提前结束等到操作
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
当线程池处于以下状态不需要关闭:
如果线程池是RUNNING状态的
如果线程池是SHUTDOWN状态并且队列中还有task(SHUTDOWN状态下还是会处理现有的task)
ThreadPoolExecutor线程池源码分析_持之以恒-CSDN博客