目录
1 前言
ThreadPoolExecutor
的基本概念和用法已经在之前的文章线程池ThreadPoolExecutor简介 、Executor框架完整解读中做过详细的说明,这里主要基于JDK1.8对ThreadPoolExecutor
从源码级别分析其实现原理。
ThreadPoolExecutor
是ExecutorService
的最重要的实现类,ThreadPoolExecutor
不直接实现ExecutorService
接口,它直接继承于AbstractExecutorService
抽象类(AbstractExecutorService的源码实现在AbstractExecutorService源码完全解析已做过分析。), AbstractExecutorService
对ExecutorSerivice
接口中的一些方法做过的默认实现 。
线程池有两个重要的概念一个是任务队列,另一个是工作者线程 。
任务队列是存放任务的容器,工作者线程会依次不断地到队列中获取任务并执行。
2 重要的成员内部类Worker
Worker
继承于AbstractQueuedSynchronizer
抽象类,它又实现了Runnable
接口。
Worker可以理解为一个工作者线程,但内部属性又不只有一个Thread属性,除此之外还有首任务firstTask、线程所完成的任务数completedTasks。
Worker
类主要是维护执行任务的线程的中断状态的控制,及其他次要的一些标记功能。它继承AQS,它相当于一个不可重入的排他锁.
1) 成员变量
thread表示Worker执行任务的线程,firstTask表示worker执行的第一个任务(对于后来的其他任务它会到任务队列中去获取),completedTasks表示当前worker线程所完成的任务数
/** Thread this worker is running in. Null if factory fails. */
final Thread thread;// 一般不为空,这由ThreadFactory决定
/** Initial task to run. Possibly null. */
Runnable firstTask;//可能为空
/** Per-thread task counter */
volatile long completedTasks;//此工作线程完成的任务数
2) 构造方法
构造方法主要涉及对成员变量的初始化,方法体内调用了父类AQS的setState方法将state置为负数-1,它的主要目的是防止线程被过早中断,直到runWorker
开始执行任务时才清除state的负数状态(成员内部类的一个对象与外部类的对象相互绑定,成员内部类可直接访问外部类的全局变量和实例、静态方法)。
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker 调用AQS的setState,设置状态
this.firstTask = firstTask;
//getThreadFactory是外部类的ThreadPoolExecutor的实例方法,返回一个实现ThreadFactory接口的对象.
//newThread根据当前worker所代表(Worker实现了Runnable接口,worker也是Runnable对象)的Runnable对象
//创建一个线程对象。所以this.thread线程启动就会执行worker.run().
this.thread = getThreadFactory().newThread(this);
}
3)方法实现
①run方法
run方法是执行任务方法,它直接委托给外部类ThreadPoolExecutor的runWorker
方法来实现,runWorker
方法的实现细节在之后会详细说明。
/** Delegates main run loop to outer runWorker */
public void run() {
//
当Worker.thread.start()调用后,Worker.thread线程启动,就会执行这里的run方法,run方法又委托给runWorker
//换句话说,worker线程启动后,最终会执行runWorker方法。
runWorker(this);
}
②与锁相关的方法
isHeldExclusively
、 tryAcquire
、tryRelease
这3个方法均是父类AQS的模板方法所调用的应被重写的方法,其具体原理在之前AbstractQueuedSynchronizer实现原理分析帖子中做过说明,这里不再细说。
lock
、 tryLock
、unlock
、isLocked
这4个方法也与显式锁ReentrantLock实现原理基本一致,之前对ReentrantLock的实现做过说明,这里也不再细说。
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) {
//与ReentrantLock的区别在于,这里未检测在释放锁前是否已获得锁
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(); }
③interruptIfStarted中断线程,调用此方法可以在任务启动后中断线程。
void interruptIfStarted() {
Thread t;
//state不能小于0,为负数表明worker线程还未启动
//(在构造方法中将state初始为-1,在worker线程启动后runWorker方法开头处的w.unLock会将state置为0)
//!t.isInterrupted()如果线程已经是中断状态,也不需要再去中断它了。
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
3 内置的拒绝策略
ThreadPoolExecutor
内部实现了4种拒绝策略,默认使用AbortPolicy
策略,这4种拒绝策略都实现RejectedExecutionHandler
接口,这4个类都是ThreadPoolExecutor
的静态内部类。当线程池执行器饱和时,会调用RejectedExecutionHandler的rejectedExecution
方法处理任务。
CallerRunsPolicy
, 使用任务提交者的所在线程执行任务;AbortPolicy
,直接抛出异常,这是默认的拒绝策略;DiscardPolicy
, 不执行任务,将任务丢弃;DiscardOldestPolicy
,丢弃队列中最近的任务,然后执行当前任务
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);
}
}
}
4 静态常量与成员变量
ThreadPoolExecutor
有一个重要的成员变量ctl
,它是一个int
型的原子变量,它是线程池执行器状态控制的主要属性。它复合了线程池执行器的两个重要状态,一个是workerCount,它表示有效线程数,另一个是runState,它表示线程池执行器是否正在运行、正在关闭等。ctl共有32个二进制位,runState占用ctl的高3位,workerCount占用ctl的低29位,可调用runStateOf(ctl)
方法来取ctl的高3位,可调用workerCountOf(ctl)
方法来取ctl的低29位,另外还可调用ctlOf(runState, workerCount)
根据runState、workerCount算出ctl的值。
//线程池主要的状态控制属性
//初始值为-536870912,二进制开形式为 0b10100000_00000000_00000000_00000000
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//workerCount在ctl中的二进制位数,占29位
private static final int COUNT_BITS = Integer.SIZE - 3; //29
//workerCount的最大值, 二进制形式 0b00011111_11111111_11111111_11111111;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;//536870911
// runState is stored in the high-order bits
//表示ctl中的最高3位的runState值
private static final int RUNNING = -1 << COUNT_BITS;//二进制形式 0b10100000_00000000_00000000_00000000
private static final int SHUTDOWN = 0 << COUNT_BITS;//二进制形式 0b00000000_00000000_00000000_00000000
private static final int STOP = 1 << COUNT_BITS;//二进制形式 0b00100000_00000000_00000000_00000000
private static final int TIDYING = 2 << COUNT_BITS;//二进制形式 0b01000000_00000000_00000000_00000000
private static final int TERMINATED = 3 << COUNT_BITS;//二进制形式 0b01100000_00000000_00000000_00000000
// Packing and unpacking ctl
private static int runStateOf(int c) {
return c & ~CAPACITY; //c & 0b11100000_00000000_00000000_00000000
}
private static int workerCountOf(int c) {
return c & CAPACITY; //c & 0b00011111_11111111_11111111_11111111
}
private static int ctlOf(int rs, int wc) {
return rs | wc; }
workerCount是已被允许启动但不允许停止的工作线程数。 该值可能与活动线程的实际数量暂时不等,例如,当ThreadFactory在被要求创建,但创建线程失败,该值会与之不等。 用户可见的线程池大小为workers.size()
(workers是一个HashSet类型的对象,它是也是一个成员变量,用来存放Worker的容器)。
runState提供线程池执行器主要的生命周期控制,它有以下几种可取的值:
- RUNNING:接受新任务并处理排队的任务
- SHUTDOWN:不接受新任务,但处理已入队的任务
- STOP:不接受新任务 、不处理已入队的任务,并中断执行中的任务
- TIDYING:所有任务已终止,workerCount为零,将线程的状态设为TIDYING,并将调用回调方法
Terminated()
- TERMINATED:方法
terminate()
已执行完
runState是有序的,它随时间单调增加,但其生命周期并非一定会经历下面的所有状态。状态转换过程是
- RUNNING -> SHUTDOWN:在调用
shutdown()
时,可能隐式在finalize()
中调用 - RUNNING/SHUTDOWN -> STOP:调用
shutdownNow()
时 - SHUTDOWN -> TIDYING:当任务队列和工作者线程池都为空时
- STOP -> TIDYING:当工作者线程池为空时
- TIDYING -> TERMINATED:当
terminate()
已执行完时
状态变为TERMINATED时,在awaitTermination()
中等待的线程将返回。
检测到从SHUTDOWN到TIDYING间的状态转换并不简单,因为在SHUTDOWN状态期间,任务队列在非空之后可能会变空,反之亦然,但是只有在看到它为空之后才能看到workerCount 为0 。
其它字段
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 final BlockingQueue<Runnable> workQueue;
private volatile ThreadFactory threadFactory;
private volatile RejectedExecutionHandler handler;
private volatile long keepAliveTime;
private volatile int corePoolSize;
private volatile int maximumPoolSize;
private volatile boolean allowCoreThreadTimeOut;
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
private static final RuntimePermission shutdownPerm =
new RuntimePermission("modifyThread");
private final AccessControlContext acc;
private static final boolean ONLY_ONE = true;
mainLock: 一个可重入的排他锁,这个锁主要是保证访问属性workers的线程安全及与之相关清除、标记 。
workers:它保存所有的工作者线程,访问此属性前必须先获得mainLock锁。
termination:一个等待条件,此属性主要为awaitTermination()
方法中的线程通信提供支持。
largestPoolSize:反映线程池实际曾达到的最大线程数 ,访问此属性前必须先获得mainLock锁。
completedTaskCount:线程池已完成的任务数,它只会在工作者线程终止时更新,访问此属性前必须先获得mainLock锁。
workQueue、 threadFactory、 handler、 keepAliveTime 、corePoolSize 、maximumPoolSize这6个属性,在之前的文章中有过说明,这里不再赘述。
allowCoreThreadTimeOut: 此属性默认为false. 如果它为false,则即使处于空闲状态,核心线程也保持活动状态; 如果为true,则核心线程使用keepAliveTime超时等待任务。
defaultHandler:默认的拒绝策略,当线程池饱和后,只要有新任务到达它就会直接抛出异常。
shutdownPerm 、acc:均是安全权限相关的字段。
ONLY_ONE: 中断时默认只中断一个工作者线程,tryTerminate
方法会用到此常量
5 构造方法
ThreadPoolExecutor
有4个构造方法,分别需要若干个参数,构造方法只简单地涉及对成员变量的初始化,其参数个数最多的构造方法共有7个参数,其他的构造方法都是直接调用这个构造方法来实现的(各个参数的含义在线程池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;
}
6 主要方法
execute是线程池执行器的入口方法,它会调用addWorker创建并启动(thread.start)工作者线程,而工作者线程启动后又会调用runWorker去执行任务。因此可以看出execute、 addWorker 、runWorker 是线程池执行器最重要的3个方法(点击绿色的方法名快速跳至目标方法)。
1) 成员变量ctl相关方法
runStateOf(ctl)
方法来取ctl的高3位,获取runState,
workerCountOf(ctl)
方法来取ctl的低29位,获取workerCount
ctlOf(runState, workerCount)
根据runState、workerCount算出ctl的值。
runStateLessThan(int,int)
返回第一个参数(表示runState)是否小于第二个参数的布尔值
runStateAtLeast
返回第一个参数(表示runState)是否大于等于第二个参数的布尔值
isRunning(int)
返回runState是否为RUNNING(接受新任务并处理排队的任务)的布尔值
compareAndIncrementWorkerCount(int)
尝试CAS更新ctl,将workerCount加1
compareAndDecrementWorkerCount(int)
尝试CAS更新ctl,将workerCount减1
decrementWorkerCount(int)
CAS自旋更新ctl,只有成功将workerCount减1,方法才能返回
advanceRunState(int targetState)
将runState设为targetState,若runState已经至少targetState级别则不改变原runState值。
private static int runStateOf(int c) {
return c & ~CAPACITY; }
private static int workerCountOf(int c) {
return c & CAPACITY; }
private static int ctlOf(int rs, int wc) {
return rs | wc; }
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect + 1);
}
private boolean compareAndDecrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect - 1);
}
private void decrementWorkerCount() {
do {
} while (! compareAndDecrementWorkerCount(ctl.get()));
}
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
2) interruptWorkers系列方法
1) interruptIdleWorkers(boolean)
interruptIdleWorkers的实现比较简单,它在执行核心逻辑之前要先获取两类锁,一个锁是mainLock锁,另一个锁是Worker本身的锁。它遍历所有Worker中对应的线程,若线程是未被中断且是空闲线程就中断此线程 。若参数onlyOne是true,则最多只会中断一个空闲线程。
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();//获取mainLock
try {
for (Worker w : workers) {
Thread t = w.thread;
//线程已经是中断状态就不再中断它
//尝试获取worker锁,允许抢锁失败。
//若抢锁失败表明worker线程正在执行任务,它不是空闲线程,准备去获取下一个worker锁
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)//onlyOne是true,就只中断一个空闲线程,然后退出
break;
}
} finally {
mainLock.unlock();
}
}
2) interruptIdleWorkers()
interruptWorkers()
中断线程池中所有的空闲线程 ,我们来看看interruptWorkers()如何实现的。
interruptIdleWorkers()
直接委托给interruptIdleWorkers(boolean)
去实现,上面已经对interruptIdleWorkers(boolean)
分析过了,这里就不再说了。
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}
3) interruptWorkers()
interruptWorkers()
中断所有已启动线程, 我们来看看interruptWorkers()如何实现的。
interruptWorkers方法很简单,它先获取mainLock锁,然后遍历所有worker线程,并中断已启动的worker线程。
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
w.interruptIfStarted();//中断已启动的worker线程(active thread,即线程的start方法已被调用)
} finally {
mainLock.unlock();
}
}
3) terminate系列方法
(1) isTerminating()
isTerminating()
返回线程池执行器是否正在被终止的布尔值,此方法不是ExecutorService接口中的方法,这是ThreadPoolExecutor自身添加的一个API。这种状态一般出现在①shutdown
、②shutdownNow
、③ tryTerminate
方法调用后(tryTerminate中CAS成功将runState更新为TIDYING但调用terminate()方法还未执行完的时候)。
public boolean isTerminating() {
int c = ctl.get();
//runState>=SHUTDOWN 且runState<TERMINATED ,那么runState则可能是SHUTDOWN、STOP、TIDYING其中之一
return ! isRunning(c) && runStateLessThan(c, TERMINATED);
}
(2) isTerminated()
isTerminating()
返回线程池执行器是否已被终止的布尔值。
public boolean isTerminated() {
//runState>=TERMINATED ,此时runState只能是TERMINATED
return runStateAtLeast(ctl.get(), TERMINATED);
}
(3) awaitTermination()
awaitTermination()阻塞等待所有任务完成。此方法需要设置超时时间,它会阻塞当前线程直到所有任务完成(返回ture)或发生超时(返回false)或当前线程被中断。
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();//获取锁
try {
for (;;) {
//runState是否为TERMINATED 。TERMINATED状态时,所有任务已终止,线程池为空。
if (runStateAtLeast(ctl.get(), TERMINATED))
//已经是TERMINATED了,返回true
return true;
if (nanos <= 0)//已经超时,返回false
return false;
//当前线程阻塞等待,
//直到“达到超时时间”或“被termination.signal通知"(tryTerminate会调用termination.signalAll) 时
//当前线程才能被唤醒
nanos = termination.awaitNanos(nanos);
}
} finally {
mainLock.unlock();
}
}
(4) tryTerminate()
tryTerminate()
检查runState否应转为TERMINATED状态,若状态应该转换则执行相应的teminate工作.
其实现细节是:
①若是在“runState是RUNNING状态”或“runState至少是TIDYING状态”或“runState是SHUTDOWN但队列中还有任务”这三种情况下,将runState不能转为TERMINATED ,方法直接返回。反之则进入下一步。
②再检查线程数workerCount是否为零,若workerCount不为零则调用interruptIdleWorkers中断一个空闲线程 ,反之则进入下一步。
③先获取mainLock锁 ,然后CAS尝试将runState设为TIDYING(这里cas更新失败将自旋重试),再然后执行terminated()
(空方法,留给子类实现)方法,待terminated()执行完后,再将runState无条件设为TERMINATED并唤醒等待termination条件的所有线程
final void tryTerminate() {
for (; ; ) {
int c = ctl.get();
if (isRunning(c) ||//runState是RUNNING状态
runStateAtLeast(c, TIDYING) || //至少是TIDYING状态
(runStateOf(c) == SHUTDOWN && !workQueue.isEmpty()))//runState是SHUTDOWN但队列中还有任务
//这三种情况下不能将runState转为TERMINATED,方法直接返回
return;
//runState可以转为TERMINATED,但池中还有一些线程,就中断池中一个空闲线程,然后方法返回
if (workerCountOf(c) != 0) {
// Eligible to terminate
interruptIdleWorkers(ONLY_ONE);//中断一个空闲线程
return;
}
//runState可以转为TERMINATED且池中没有任何线程时
//
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//尝试CAS更新,将runState设为TIDYING
// (TIDYING状态表示所有任务都已终止且线程数workerCount为零)
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated();//空方法,留后子类实现
} finally {
//terminated执行后,无条件地将runState设为TERMINATED状态
//(TERMINATED状态表示terminated方法执行完成)
ctl.set(ctlOf(TERMINATED, 0));
//唤醒等待termination条件的所有线程
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
4 )addWorker系列方法
(1) addWorker(Runnable,boolean)
addWorker是一个重要的方法,它的主要作用是启动工作者线程Worker,其返回值表示启动Worker是否成功。它有两个参数,第一个参数是新创建线程的第一个执行的任务(可以为空),第二个参数是表示是否为核心线程的布尔值.
它的主要逻辑分为两部分
①第一部分是两层for循环自旋,它主要是检查runState、workerCount,并将workerCount加1 。
细节上是:先检查执行器是被关闭且工作队列为空,若是,则直接返回false。然后再检查线程数是否超出给定的边界值(核心线程数或可允许最大线程数值),若超出则直接返回false。尝试CAS更新workerCount,将workerCount加1,若CAS更新成功,则退出for循环,进入下一部分,若CAS更新失败,则需再次进入内循环自旋重试。若runState被其他线程修改了,则要重新进入外层循环重试。
②第二部分主体是一个try-finally块,它主要先获取mainLock锁,再向成员变量workers中添加一个worker对象,若添加失败则调用addWorkerFailed进行回滚。
细节上是:先尝试创建并启动一个新的worker。如果线程工厂无法创建线程(创建的线程为null),将返回false。 如果线程池已停止或即将关闭,也将返回false。 如果worker线程启动失败(由于线程工厂返回null或发生异常),将调用addWorkerFailed进行回滚。
private boolean addWorker(Runnable firstTask, boolean core) {
/**
* 主要是检查runState 和workerCount,时机合适就将workerCount加1
*/
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);//获取runState
// Check if queue empty only if necessary.
//如果线程池已关闭且工作队列为空,添加Worker失败,直接返回false
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);//获取线程数workerCount
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))//不能大于corePoolSize 、maximumPoolSize
//线程数大于规定的线程数(最大容量的线程数,配置的核心线程数、配置的可允许最大线程数)
// ,添加Worker失败,返回false
return false;
if (compareAndIncrementWorkerCount(c))//CAS失败,需要再次进入内循环自旋重试
//workerCount加1成功,退出外层for循环 ,线程数已更新,
// 接下来进入实际添加的向成员变量workers中Worker操作
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)//runState被其他线程修改了,需要跳到外层for循环的开头处重试
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
/**
* 向成员变量workers中添加worker,
* 若无法添加worker或线程启动失败,则要调用addWorkerFailed进行回滚
*/
boolean workerStarted = false;//worker线程是否启动的标志
boolean workerAdded = false;//worker是否添加成功的标记
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
//t是线程工厂创建出来的线程,可以自己重写ThreadFactory接口的newThread方法,
// newThread返回值是否为空不确定,这里有必要对t进行非空判断
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());
//线程池处于RUNNING状态或虽处于SHUTDOWN状态但任务为空 ,总之线程池还是可用的
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
//预先检查线程是否已经被启动了
if (t.isAlive()) // precheck that t is startable
//线程已预先被启动了,抛出异常
throw new IllegalThreadStateException();
workers.add(w);//添加worker对象到workers集合中
int s = workers.size();
//检查更新largestPoolSize(表示线程池实际曾达到的最大线程数)
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;//更新worker是否添加成功的标记
}
} finally {
mainLock.unlock();//释放锁
}
if (workerAdded) {
//worker成功添加后,启动线程
t.start();//**worker.run方法将执行,worker.run又会调用runWorker()
workerStarted = true;//更新worker线程是否启动的标志
}
}
} finally {
if (! workerStarted)
//添加worker失败,(根据前面的逻辑可看出,在未发生异常时,workerAdded若是false,workerStarted则也为false)
//就调用addWorkerFailed(),对addWorker方法进行回滚
addWorkerFailed(w);
}
return workerStarted;
}
(2) addWorkerFailed(Worker)
addWorkerFailed
主要是回滚创建worker线程的失败。
它先要获取mainLock锁,然后它做了3件事:
①从workers中移除这个worker;
②将workerCount减1;
③检查runState否应转为TERMINATED状态,若是则执行相应的teminate工作。
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();//先获取锁
try {
if (w != null)
workers.remove(w);//从workers中移除worker
decrementWorkerCount();//将workerCount减1
tryTerminate();//尝试终止线程池
} finally {
mainLock.unlock();
}
}
5) runWorker相关方法
(1) runWorker(Worker)
runWorker(Worker)
主要是循环往复地从任务队列中获取任务执行。核心逻辑:
①将Worker的state从-1置为0(调用worker.unlock),保证之后worker线程能被中断、worker锁能被获取。
②到worker.firstTask属性或任务队列中获取任务。若获取的任务不为空就进入下一步,反之则worker线程准备终止,进入步骤6。
③获取woker锁,准备执行任务。
④检查runState,若runState是STOP级就确保当前线程是中断的,若runState不是STOP级就确保当前线程之后不是中断的。
⑤调用task.run开始执行任务,捕获执行任务过程中可能出现的异常。在任务执行完后,将worker的任务完成数completedTasks加1,再释放worker锁。再次获取任务,跳回步骤2。
⑥在worker线程即将终止退出(包括因异常退出的情况)时,执行processWorkerExit方法处理worker终止的后续工作
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;//
//在获取w.firstTask后,将w.firstTask设为空,因为之后worker会到任务队列中获取任务
w.firstTask = null;
//这里并不是真的释放锁,而只是将父类AQS的state从初始的-1置为0。
//否则worker线程不能被中断(worker初始化时state为-1,interruptIfStarted方法中要求state>0才中断线程),
//worker锁也一直无法被获取(尝试获取锁时compareAndSetState(0, 1)返回true才能成功抢锁,若state为-1,它永远返回false)
w.unlock(); // allow interrupts
boolean completedAbruptly = true; //worker异常终止的标志
try {
//firstTask不空或任务队列中还能获取到任务,
while (task != null || (task = getTask()) != null) {
//成功获取到worker锁后,表明worker线程就要执行任务,不再是空闲状态了。
//w.isLock可以判断线程是否空闲等待,如果返回false,表明worker线程在空闲等待
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
//如果runState是STOP且线程未被中断,就使用wt.interrupt()中断线程,确保wt是中断的;
//如果runState不是STOP就用Thread.interrupted()保证之后wt不是中断状态
//(若某线程t是中断状态,调用静态方法Thread.interrupted()会在清除线程t的中断标记后
//返回true,下次调用实例方法t.isInterrupted()将返回false,这是因为中断标记之前已被清除)
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++;//已完成任务数加1
w.unlock();
}
}
completedAbruptly = false;//worker没有因异常死亡
} finally {
processWorkerExit(w, completedAbruptly);//清除和标记woker终止后的后续工作
}
}
(2) getTask()
getTask()
从任务队列获取任务。其核心逻辑:
①检查runState,若runState状态表明执行器不需要再执行任务(“runState>=STOP” 或 “runState>=SHUTDOWN且任务队列为空”)时,将workerCount减1,返回空任务,此worker线程即将终止。反之则进入下一步
②若当前线程数大于maximumPoolSize或等待任务出队超时或任务队列为空时,就尝试CAS将workerCount减1,反之则进入步骤3。 若CAS更新workerCount成功则返回空任务,反之则自旋重试,跳回步骤1。
③阻塞等待任务出队,如果任务出队成功,就返回这个任务,反之则自旋重试,跳回步骤1。
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.
//“runState>=STOP” 或 “runState>=SHUTDOWN且任务队列为空”,
// 表明执行器已经关闭了,worker线程将终止,返回空任务,worker不再执行任务。
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();//因工作线程退出,workerCount减1
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
//是否要应用超时策略的布尔值(中断空闲线程)
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//wc > maximumPoolSize workerCount大于maximumPoolSize,因为maximumPoolSize被重设了
// timed && timedOut 在运用超时策略时最终还真的等待超时了
// "wc >1 || workQueue.isEmpty()"当前只有一个线程或任务队列空了
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
//尝试CAS将workState减1
if (compareAndDecrementWorkerCount(c))
//CAS更新成功,返回空任务
return null;
continue;//CAS更新失败,自旋重试获取任务
}
try {
//如果要应用超时策略,就等待指定时长让任务出队,
//若不应用超时策略,就无限长时间地等待任务出队
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;//成功出队了,返回此任务
timedOut = true;//poll返回null,等待超时了
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
(3) processWorkerExit(Worker,boolean)
processWorkerExit(Worker,boolean)
处理worker线程终止退出的后续扫尾工作。
其主要逻辑:
①若worker线程是因异常而突然终止的,就将workerCount减1
②获取manLock锁,将worker.completedTasks同步到ThreadPoolExecutor.completedTaskCount中,从workers中移除这个即将终止的worker
③检查runState是否应转为TERMINATED状态及与之相关的处理
④当runState<=STOP时,如果时机合适就启动一个新worker来替代即将终止的worker
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
//worker因异常而终止,workerCount不能自适应改变,手动将workerCount减1
decrementWorkerCount();//
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//当一个worker终止时,需要将其completedTasks同步到ThreadPoolExecutor.completedTaskCount上
completedTaskCount += w.completedTasks;
workers.remove(w);//从成员变量workers中移除这个worker
} finally {
mainLock.unlock();
}
tryTerminate();//检查runState是否应转为TERMINATED状态及与之相关的处理
int c = ctl.get();
//runState是RUNNING或SHUTDOWN时,这两种情况下还可以启动worker
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
//worker正常死亡时 判断是需要启动新worker来替代已死的worker
//min表示线程池中能长久驻存的线程数(不会因长久空闲等待而终止的线程数)
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
//只有一个长久驻存的线程但队列中还有任务
min = 1;
if (workerCountOf(c) >= min)
//当前线程数多于能长久驻存的线程数,不需要启动新worker来替代已死的worker,直接返回
return; // replacement not needed
}
//启动新的worker替代已死worker
addWorker(null, false);
}
}
6) execute(Runnable)
execute(Runnable)方法非常重要,它是ThreadPoolExecutor的入口方法,父类AbstractExecutorService已实现ExecutorService接口中的sumbit 、invokeXXX方法,这些方法的核心逻辑都委托给execute实现,详细说明见之前的文章AbstractExecutorService源码完全解析。
execute(Runnable)的核心逻辑分为三步:
①如果当前有效线程数少于corePoolSize,则调用addWorker尝试启动一个核心线程执行任务。若成功启动,方法就直接返回,反之则进入下一步。
②若执行器还在运行(runState=RUNNING)且任务入队成功,则需要再次检查workerCount和runState, 反之则进入步骤3。若执行器已关闭(runState>RUNNING)且成功将刚入队的任务从队列中移除,则使用拒绝策略处理此任务;反之再检查当前有效线程数是否为零,若实际线程数为零,则新启动一个非核心线程(保证线程池中至少有一个线程)。
③(一般是队列已满)尝试启动一个非核心线程去执行此任务。 如果启动失败则表明执行器已关闭或已饱和,因此使用拒绝策略处理此任务。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get(); //先获取原子变量ctl的值
//工作者线程数少于corePoolSize,
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))//尝试创建核心线程执行任务
return;//成功就返回
c = ctl.get();//若失败(可能是执行器被关闭了或线程启动失败),要重新获取ctl值
}
//工作者线程数大于等于corePoolSize,意味着要尝试将任务放入队列到队列中
//isRunning(c)线程池能接受任务
//workQueue.offer(command)任务入队成功
if (isRunning(c) && workQueue.offer(command)) {
//重新获取ctl,将再次检查runState和workerCount因为有可能上次检查后线程被终止了或线程池被关闭了
int recheck = ctl.get();
//线程池已关闭时尝试将这个已入队的任务从队列中移除(上面的"workQueue.offer(command)"已成功入队)
if (! isRunning(recheck) && remove(command))
//移除任务成功时,使用拒绝策略处理任务
reject(command);//
//"线程池已关闭且从任务队列中移除任务失败(可能是任务已被完成了)" 或"线程池还处于RUNNING状态"
//将检查池中的线程数是否为0
else if (workerCountOf(recheck) == 0)
//线程数为零时, 创建非核心线程,但不立即执行任务(这里的addWorker中的Runnable为空)
// 因为之前已经将此任务放入工作队列了,空闲线程会到队列中去获取任务来执行
addWorker(null, false);
}
//入队失败,可能是因为队列已满,尝试创建一个非核心线程去执行任务
else if (!addWorker(command, false))
//addWorker失败,使用拒绝策略处理任务
reject(command);
}
上面的execute中调用了几个我们不熟悉的方法,分别是remove(Runnable)
、reject(Runnable)
,下面我们分别来看看这两个方法。
(1) remove(Runnable)
remove(Runnable)
方法逻辑很简单,就是先将任务从任务队列中移除,再调用tryTerminate()检查是否应转为TERMINATED状态及其相关的处理,最后返回是否成功移除任务的布尔值。
public boolean remove(Runnable task) {
boolean removed = workQueue.remove(task);
tryTerminate(); // In case SHUTDOWN and now empty
return removed;
}
(2) reject(Runnable)
reject(Runnable)
直接委托给拒绝策略handler调用rejectedExecution方法。
handler是实现RejectedExecutionHandler接口的对象,表示线程池饱和时的饱和策略rejectedExecution是此接口的唯一方法,它一般在构造方法中指定。
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
7) shutdown系列方法
(1) shutdown()
shutdown()
方法是用来关闭线程池执行器的,它的主要逻辑是:
先将runState至少设为SHUTDOWN级,然后中断池中的空闲线程,调用onShutdown空方法(钩子函数,留给子类实现),最后检查runState是否应转为TERMINATED状态及与之相关的处理。
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();//先获取锁
try {
checkShutdownAccess();//检查权限
advanceRunState(SHUTDOWN);//若runState已至少是STOP级就不做任何处理,反之将runState设为STOP,
interruptIdleWorkers();//中断池中的空闲线程
//空方法,留后子类实现,它是一个钩子函数 其子类ScheduledThreadPoolExecutor重写了此方法
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();//检查runState是否应转为TERMINATED状态及与之相关的处理
}
(2) shutdownNow()
shutdownNow()
方法是用来立即关闭线程池执行器的,它的主要逻辑是:
先将runState至少设为STOP级,然后中断所有已启动的线程,再从任务队列中移除所有待执行的任务,再然后检查runState是否应转为TERMINATED状态及与之相关的处理,最后返回这些待执行的任务列表。
可以看出shutdown
和shutdownNow
之间的区别在于:
①shutdown将runState至少设为SHUTDOWN,而shutdownNow将runState至少设为STOP.
②shutdown只中断空闲线程,而shutdownNow会中断所有线程。换而言之,shutdown不去停止正在执行的任务,而shutdownNow会让正在执行的任务(如果任务能响应中断的话)停止。
③shutdown不去任务队列中移除任务,而shutdownNow会从任务队列中移除所有的任务。换而言之,shutdown之前提交的任务还能被执行,而shutdownNow之前提交的任务不能被执行了。
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();//先获取锁
try {
checkShutdownAccess();//检查权限
advanceRunState(STOP);//若runState>STOP就不做任何处理,反之将runState设为STOP,
//中断所有已启动的线程(包括正在执行任务的非空闲线程和等待任务的空闲线程),不响应中断的任务可能无法被终止
interruptWorkers();
tasks = drainQueue();//从队列中移除所有任务
} finally {
mainLock.unlock();
}
tryTerminate();//检查runState是否应转为TERMINATED状态及与之相关的处理
return tasks;
}
shutdownNow()方法体中调用drainQueue()从队列中移除所有任务, 我们来看看drainQueue()如何做的。
① drainQueue()
drainQueue
所实现的逻辑很简单:它只将将工作队列中的所有任务移除,并将这些任务返回。
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = workQueue;
ArrayList<Runnable> taskList = new ArrayList<Runnable>();
q.drainTo(taskList);//BlockingQueue的drainTo方法会一次性取出所有可用元素,在取出后会在队列中删除这些元素。
if (!q.isEmpty()) {
//DelayQueue等类型的队列直接出队可能失败,再次用remove方法获取之前出队失败的元素。
for (Runnable r : q.toArray(new Runnable[0])) {
if (q.remove(r))
taskList.add(r);
}
}
return taskList;
}
(3) isShutdown()
isShutdown()
返回线程池执行器是否被关闭的布尔值。从方法实现上可以看出,它是根据runState的值判断线程池执行器是否被关闭,只要runState不小于SHUTDOWN,执行器就是关闭状态。
public boolean isShutdown() {
return ! isRunning(ctl.get());
}
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
8) 配置相关setter/getter
(1) ThreadFactory
setThreadFactory/getThreadFactory用于设置/获取线程工厂,只要实现ThreadFactory接口就可以自定义线程工厂。
public void setThreadFactory(ThreadFactory threadFactory) {
if (threadFactory == null)
throw new NullPointerException();
this.threadFactory = threadFactory;
}
public ThreadFactory getThreadFactory() {
return threadFactory;
}
(2) RejectedExecutionHandler
setRejectedExecutionHandler/getRejectedExecutionHandler用于设置/获取饱和策略,当线程池和队列均已满时,调用RejectedExecutionHandler.rejectedExecution处理新任务。
public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
if (handler == null)
throw new NullPointerException();
this.handler = handler;
}
public RejectedExecutionHandler getRejectedExecutionHandler() {
return handler;
}
(3) CorePoolSize
setCorePoolSize/getCorePoolSize用于设置/获取核心线程数
public void setCorePoolSize(int corePoolSize) {
if (corePoolSize < 0)
throw new IllegalArgumentException();
int delta = corePoolSize - this.corePoolSize;
this.corePoolSize = corePoolSize;//更新corePoolSize属性
//如果实际线程数已经多于最新的corePoolSize,就中断所有空闲线程。
if (workerCountOf(ctl.get()) > corePoolSize)
interruptIdleWorkers();
//“当前实际线程数少于新corePoolSize”且"新corePoolSize大于原来的corePoolSize" 时
//就预先启动足够的新worker线程(最大为新的corePoolSize)以处理队列中的当前任务数,
//但是如果在添加worker过程中队列变为空则停止添加。
else if (delta > 0) {
// We don't really know how many new threads are "needed".
// As a heuristic, prestart enough new workers (up to new
// core size) to handle the current number of tasks in
// queue, but stop if queue becomes empty while doing so.
int k = Math.min(delta, workQueue.size());
while (k-- > 0 && addWorker(null, true)) {
if (workQueue.isEmpty())
break;
}
}
}
public int getCorePoolSize() {
return corePoolSize;
}
prestartCoreThread()
方法启动一个核心线程,若所有核心线程已启动则返回false.
ensurePrestart()
方法与prestartCoreThread()
类似,但它能保证池中至少有一个线程。
prestartAllCoreThreads()
方法将一次性启动所有核心线程,若所有核心线程已启动将返回0。
public boolean prestartCoreThread() {
//当前线程数小于corePoolSize就创建一个核心线程
return workerCountOf(ctl.get()) < corePoolSize &&
addWorker(null, true);
}
void ensurePrestart() {
int wc = workerCountOf(ctl.get());
if (wc < corePoolSize)
//当前线程数小于corePoolSize创建一个核心线程
addWorker(null, true);
else if (wc == 0)
//corePoolSize为0,当前线程数也为0,就创建一个非核心线程。池中至少有这个刚启动的线程了
addWorker(null, false);
}
public int prestartAllCoreThreads() {
int n = 0;
while (addWorker(null, true))//一次性启动所有核心线程
++n;
return n;//返回此方法启动的核心线程数
}
(4) MaximumPoolSize
setMaximumPoolSize/getMaximumPoolSize用于设置/获取最大可允许创建的线程数
public void setMaximumPoolSize(int maximumPoolSize) {
if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)
throw new IllegalArgumentException();
this.maximumPoolSize = maximumPoolSize;//更新maximumPoolSize属性
//若当前实际的线程数多于新的maximumPoolSize,就中断所有空闲线程
if (workerCountOf(ctl.get()) > maximumPoolSize)
interruptIdleWorkers();
}
public int getMaximumPoolSize() {
return maximumPoolSize;
}
(5) KeepAliveTime
setKeepAliveTime/setKeepAliveTime用来设置/获取线程的最大空闲时间。
public void setKeepAliveTime(long time, TimeUnit unit) {
if (time < 0)
throw new IllegalArgumentException();
if (time == 0 && allowsCoreThreadTimeOut())
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
long keepAliveTime = unit.toNanos(time);
long delta = keepAliveTime - this.keepAliveTime;
this.keepAliveTime = keepAliveTime;//更新maximumPoolSize属性
if (delta < 0)//新的keepAliveTime小于原keepAliveTime,就中断所有空闲线程
interruptIdleWorkers();
}
//处理KeepAliveTime的时间单位转换
public long setKeepAliveTime(TimeUnit unit) {
return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
}
public long getKeepAliveTime(TimeUnit unit) {
return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
}
默认情况下keepAliveTime,只适用于非核心线程,即核心线程不会因空闲等待太久而被终止, 但使用allowCoreThreadTimeOut()方法并将参数设为true就可改变这种默认效果,使keepAliveTime对核心线程同样有效。
public boolean allowsCoreThreadTimeOut() {
return allowCoreThreadTimeOut;
}
public void allowCoreThreadTimeOut(boolean value) {
if (value && keepAliveTime <= 0)
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
if (value != allowCoreThreadTimeOut) {
allowCoreThreadTimeOut = value;//更新allowCoreThreadTimeOut属性
if (value)//若允许核心线程超时,就中断所有空闲线程
interruptIdleWorkers();
}
}
(6) WorkQueue
getQueue用于获取任务队列。
public BlockingQueue<Runnable> getQueue() {
return workQueue;
}
9) 状态监控相关方法
(1) getPoolSize()
getPoolSize()
返回当前线程池中的工作线程总数
public int getPoolSize() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Remove rare and surprising possibility of
// isTerminated() && getPoolSize() > 0
//若runState是TIDYING或TERMINATED时,workerCount一定为0(之前在tryTerminate中分析过)
//反之就取workers.size()
return runStateAtLeast(ctl.get(), TIDYING) ? 0
: workers.size();
} finally {
mainLock.unlock();
}
}
(2) getActiveCount()
getActiveCount()
返回当前活动(正在执行任务)的工作线程数
public int getActiveCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int n = 0;
for (Worker w : workers)
if (w.isLocked())//Worker锁被持有,表示正在执行任务
++n;
return n;
} finally {
mainLock.unlock();
}
}
(3) getLargestPoolSize()
getLargestPoolSize()
返回曾经创建过的最大线程数。通过这个数据可以知道线程池是否曾经满过。如该数值等于线程池的最大大小,则表示线程池曾经满过。
public int getLargestPoolSize() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
return largestPoolSize;
} finally {
mainLock.unlock();
}
}
(4) getTaskCount()
getTaskCount()
返回执行器从启动到现在所接受的任务总数。
public long getTaskCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
long n = completedTaskCount;//先获取表示完成的任务数的成员变量completedTaskCount
for (Worker w : workers) {
//还有一些记录有worker中的已完成任务数(尚未同步到completedTaskCount中)
n += w.completedTasks;
//另外还要加上正在执行的任务(还未完成)
if (w.isLocked())//此worker正在执行任务
++n;
}
return n + workQueue.size();//最后加上任务队列中的任务数
} finally {
mainLock.unlock();
}
}
(5) getCompletedTaskCount()
getCompletedTaskCount()
返回执行器完成的任务总数。
public long getCompletedTaskCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
long n = completedTaskCount;//先获取表示完成的任务数的成员变量completedTaskCount
for (Worker w : workers)
//还有一些记录有worker中的已完成任务数(尚未同步到completedTaskCount中)
n += w.completedTasks;
return n;
} finally {
mainLock.unlock();
}
}
(6) 空实现的钩子函数
除此之外,线程池还提供了3个空方法,beforeExecute
方法在执行一个任务前被调用,afterExecute
方法在一个任务完成后被调用,terminated()
方法在线程池停止时被调用。
我们可继承ThreadPoolExecutor
来实现自己的线程池,并以此为基础重写这3个方法来实现自己的监控逻辑。
10) finalize()
finalize()方法是顶级父类Object的方法,此方法在对象被GC回收前调用,一般用来清理释放占用的资源。ThreadPoolExecutor重写了此方法,其核心逻辑是调用shutdown()
方法关闭执行器。
protected void finalize() {
SecurityManager sm = System.getSecurityManager();
if (sm == null || acc == null) {
shutdown();
} else {
PrivilegedAction<Void> pa = () -> {
shutdown(); return null; };
AccessController.doPrivileged(pa, acc);
}
}
7 工作流程
以sumbit(Runnable/Callable)方法为例,说明线程池执行器ThreadPoolExecutor的主要工作流程。
sumbit(Runnable/Callable)在父类AbstractExecutorService中已有基本实现,但其核心逻辑execute方法仍要子类实现,所以ThreadPoolExecutor实现了excute方法。
submit(Runnable/Callable)方法的主要工作流程:
①它先将Runnable/Callable任务统一封装成FutureTask。那么FutureTask是如何封装原始任务的? FutureTask将Runnable或Callable任务设为它的(若原任务的类型是Runnable就使用适配器模式将其适配为Callable类型)Callable类型属性callable;另外FutureTask也实现了Runnable接口,而它的run()方法核心内容就是执行callable.call、并记录任务结果或任务执行发生的异常信息
②然后执行execute(task)的核心逻辑是addWorker(), addWorker()会启动一个新的工作线程,即worker.thread启动。worker.thread线程启动后,worker.thread线程将执行worker.run()方法,而worker.run()方法又委托给外部类ThreadPoolExecutor的runWorker方法实现。
③runWorker基本逻辑是:循环往复从worker.firstTask或工作队列中获取并执行任务 。若获取的任务为空,此线程不再执行任务,worker.run方法将结束,此线程即将终止。若获取到任务不为空就调用FutureTask.run执行任务. 这里的FutureTask.run执行会FutureTask.callable.call()并记录任务结果或发生的异常。这里的callable.call()才是最原始的任务执行内容。