线程池主要是为了减少任务执行的消耗(比如说创建线程的开销)和管理系统资源,今天我们来分析一下相关源码
继承关系如下:
我们自顶向下一个个进行分析
Executor
void execute(Runnable command);
这个接口只有一个方法,用于执行给定的任务command,很简单没啥好说的,这个类只要将任务的创建和调度分离开来,至于任务如何调度则需要看具体实现。
ExecutorService
可以看到ExecutorService继承自Executor,在原来的基础上提供了一些终止服务和提交任务(Runnable/Callable)的方法(这些方法返回的都是Future)。
方法 | 说明 |
---|---|
submit | 提交任务,不等待任务完成就立即返回Future |
invokeAll | 批量提交任务,任务完成后返回Future列表 |
invokeAny | 批量提交任务,有一个任务完成就返回Future |
shutDown | 调度器不会再接收新的任务,关闭调度器,但是不等待正在运行的任务执行完毕就立即返回了 |
shutDownNow | 调度器不会再接收新的任务,尝试关闭已经在执行的任务后再关闭调度器,但是不等待正在运行的任务执行完毕就立即返回,返回的是未执行的任务列表 |
awaitTermination | 阻塞等待所有任务执行完毕后返回,这个方法在shutDown或shutDownNow先执行后再执行 |
isShutDown | 判断调度器是否关闭 |
isTerminated | 判断调度器在关闭后所有任务是否都执行完毕,这个方法只在shutDown或shutDownNow执行完毕后才有可能返回true |
AbstractExecutorService
AbstractExecutorService是一个实现了ExecutorService的抽象类,从上图它实现的方法我们就可以知道,这个类提供了调度器如何调度任务的默认实现。我们先来看下最简单的调度方法submit的默认实现:
Future<?> submit(Runnable task)
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
可以看到task被重新封装成RunnableFuture对象后再被执行,核心代码是第二行,我们来看下具体的代码
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
好吧,只是简单的构造一个FutureTask对象后直接返回,没啥好说的,其它的submit调度方法也跟它差不多
List<Future> invokeAll(Collection<? extends Callable> tasks)
if (tasks == null)
throw new NullPointerException();
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks) {
RunnableFuture<T> f = newTaskFor(t);
futures.add(f);
execute(f);
}
for (int i = 0, size = futures.size(); i < size; i++) {
Future<T> f = futures.get(i);
if (!f.isDone()) {
try {
f.get();
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
done = true;
return futures;
} finally {
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
整个逻辑为:先执行所有任务,在等待所有任务执行完毕再返回。
List<Future> invokeAll(Collection<? extends Callable> tasks, long timeout, TimeUnit unit)
if (tasks == null)
throw new NullPointerException();
long nanos = unit.toNanos(timeout);
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks)
futures.add(newTaskFor(t));
final long deadline = System.nanoTime() + nanos;
final int size = futures.size();
// Interleave time checks and calls to execute in case
// executor doesn't have any/much parallelism.
for (int i = 0; i < size; i++) {
execute((Runnable)futures.get(i));
nanos = deadline - System.nanoTime();
if (nanos <= 0L)
return futures;
}
for (int i = 0; i < size; i++) {
Future<T> f = futures.get(i);
if (!f.isDone()) {
if (nanos <= 0L)
return futures;
try {
f.get(nanos, TimeUnit.NANOSECONDS);
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
} catch (TimeoutException toe) {
return futures;
}
nanos = deadline - System.nanoTime();
}
}
done = true;
return futures;
} finally {
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
加上了一个超时判断,如果超时就立即返回
T invokeAny(Collection<? extends Callable> tasks, long timeout, TimeUnit unit)
return doInvokeAny(tasks, true, unit.toNanos(timeout));
好吧,我们直接看doInvokeAny方法就行。。。
if (tasks == null)
throw new NullPointerException();
int ntasks = tasks.size();
if (ntasks == 0)
throw new IllegalArgumentException();
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
// For efficiency, especially in executors with limited
// parallelism, check to see if previously submitted tasks are
// done before submitting more of them. This interleaving
// plus the exception mechanics account for messiness of main
// loop.
try {
// Record exceptions so that if we fail to obtain any
// result, we can throw the last exception we got.
ExecutionException ee = null;
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Iterator<? extends Callable<T>> it = tasks.iterator();
// Start one task for sure; the rest incrementally
futures.add(ecs.submit(it.next()));
--ntasks;
int active = 1;
for (;;) {
Future<T> f = ecs.poll();
if (f == null) {
if (ntasks > 0) {
--ntasks;
futures.add(ecs.submit(it.next()));
++active;
}
else if (active == 0)
break;
else if (timed) {
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
if (f == null)
throw new TimeoutException();
nanos = deadline - System.nanoTime();
}
else
f = ecs.take();
}
if (f != null) {
--active;
try {
return f.get();
} catch (ExecutionException eex) {
ee = eex;
} catch (RuntimeException rex) {
ee = new ExecutionException(rex);
}
}
}
if (ee == null)
ee = new ExecutionException();
throw ee;
} finally {
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
逻辑如图:
ThreadPoolExecutor
分析完顶层类的代码,这个类就很好分析了,因为源代码也就2000来行~
我们先来看下最丰富的构造方法
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;
}
结合这些参数,我们先来安利一波线程池的工作流程然后在分析源码。
当我们通过调度方法(submit/invokeAll/invokeAny/execute)执行任务时,线程池的处理逻辑如下,假设当前吃中线程的数量为T,workQueue中任务的数量为W,workQueue的容量为C:
条件 | 说明 | 工作方式 |
---|---|---|
T < corePoolSize | 线程数小于corePoolSize | 创建一个新线程去执行任务,就算池中还有空闲的线程 |
T = corePoolSize && W < C | 线程数等于corePoolSize | 将任务存入workQueue队列,直到队列满 |
T < maximumPoolSize && W = C | 队列已满时 | 创建一个新线程,直到线程数等于maximumPoolSize |
T = maximumPoolSize && W = C | 线程数等于maximumPoolSize且队列已满 | 执行RejectedExecutionHandler |
我们注意到构造函数的参数中有一个keepAliveTime ,这个参数的作用是当线程数大于corePoolSize时,多余的线程如果空闲时间超过keepAliveTime,则线程被回收,所以我们可以知道线程预热一段时间后线程池中最小的线程数是corePoolSize
线程在workQueue的类型不同时,工作方式也会有不同
队列 | 工作方式 |
---|---|
SynchronousQueue | 任务永远不会存储这个队列中,队列将任务直接传递给线程,使用这个队列我们一般将maximumPoolSizes设置为无限Integer.MAX_VALUE,如果线程数设置的过小,当任务的生产大于消费的速度多余的任务肯定会被拒绝,如果线程数设置的过大,当任务的生产远远大于消费的速度时,线程会增长到一个很大的数值,所以这个队列需要谨慎使用 |
LinkedBlockingQueue | 如果构造这个队列的参数值为Integer.MAX_VALU,则这个队列就是无界队列,当线程数达到corePoolSize时且没有线程空闲时任务就会被存放在队列中,当任务的生产远远大于消费的速度时,队列中的任务数就会很大 |
ArrayBlockingQueue | 有界队列,可以控制系统资源的消耗,但是如果队列大线程少,虽然可以减少系统资源的使用但是也会导致任务吞吐量的降低,如果队列小线程大,会使系统资源繁忙的同时也有可能导致任务吞吐量降低,比如在线程上下文切换过于频繁的情况下 |
ok,我们现在再来看代码,我们知道AbstractExecutorService调度方法执行时都会默认调用execute方法,所以我们以executor为入口来法分析代码,我们先来分析下一些变量和内部类
// runState(rs)指的是线程的运行状态
// workCount(wc)指的是线程池中线程的数量
//整数ctl(control),二进制表示总共是32位,这个变量高3位存储runState,低29位存储workCount
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 29,指的是wc的有效位数
private static final int COUNT_BITS = Integer.SIZE - 3;
// 1 << 29 = 001 000...(29个0)
// (1 << 29) - 1 = 000 111...(29个1)
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// 下面五个变量定义线程池的运行状态runState
// -1 << 29 = -001 000...(29个0)
private static final int RUNNING = -1 << COUNT_BITS;
// 0 << 29 = 000 000...(29个0)
private static final int SHUTDOWN = 0 << COUNT_BITS;
// 1 << 29 = 001 000...(29个0)
private static final int STOP = 1 << COUNT_BITS;
// 2 << 29 = 010 000...(29个0)
private static final int TIDYING = 2 << COUNT_BITS;
// 3 << 29 = 011 000...(29个0)
private static final int TERMINATED = 3 << COUNT_BITS;
/**
/* ~CAPACITY的值为111 000...(29个0),c & ~CAPACITY的意思其实就是将c的低
/* 29位置0,高3位保留,因为c的高3位保存的是runState,所以计算的结果就是
/* runState
*/
private static int runStateOf(int c) { return c & ~CAPACITY; }
/**
/* CAPACITY的值000 111...(29个1),c & CAPACITY的意思其实就是保留c的低
/* 29位不变,高3位置0,因为c的低29位保存的workerCount,所以计算的结果就是
/* workerCount,可见workerCount的最大值就是CAPACITY
*/
private static int workerCountOf(int c) { return c & CAPACITY; }
/**
/* rs肯定是*** 000...(29个0),wc肯定是000 ???(29位)
/* rs | wc = *** ???(29位),相当于把rs保存在整数的高3位,
/* wc保存在整数的低29位
*/
private static int ctlOf(int rs, int wc) { return rs | wc; }
我们来看下每个rs下线程池的处理逻辑
rs | 说明 |
---|---|
RUNNING | 线程池接受新的任务,运行队列中的任务 |
SHUTDOWN | 线程池不接受新的任务,但是仍会运行队列中的任务 |
STOP | 线程池不接受新的任务,不会运行队列中的任务,打断正在运行中的任务 |
TIDYING | 所以任务都终止了,wc == 0,线程池一旦到达这个状态,就会执行terminated() |
TERMINATED | terminated执行完毕 |
线程池在设计rs的时候,它们的值有以下特点
RUNNING < SHUTDOWN < STOP < TIDYING < TERMINATED
线程池的rs变换也有这个特点:rs只能单调自增,但是不一定会经历每一个阶段。
状态转换 | 触发条件 |
---|---|
RUNNING -> SHUTDOWN | shutdown() |
(RUNNING or SHUTDOWN) -> STOP | shutdownNow() |
SHUTDOWN -> TIDYING | 线程池和队列都空了 |
STOP -> TIDYING | 当线程池空了 |
TIDYING -> TERMINATED | terminated()执行完 |
如何递增rs,线程池还专门提供了一个方法
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
/**
/* runStateAtLeast(c, targetState) 返回true 表明rs已经比targetState大了,不需要再自增,
/* 为啥第一个参数是c,而不是runStateOf(c)呢?
/* 因为rs在c的高3位,当c.rs != targetState比较大小只取决于高3位
/* 当c.rs == targetState时,c肯定大于等于targetState
/* 所以这个就可以节省一次方法调用
/* ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))) CAS设置rs,如果失败,说明存在并发,则继续自旋
*/
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
// 顾名思义,检查s的值至少是c
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
其实所谓线程池中存储的并不是Thread,而是Worker,我们一般称之为工作线程,在线程池中用一个Set存储
/**
* Set containing all worker threads in pool. Accessed only when
* holding mainLock.
*/
private final HashSet<Worker> workers = new HashSet<Worker>();
/**
/* 这是线程池中实际存储的对象,封装了线程和任务,可以统计线程总共执行了多少任务
/* 继承AQS的并实现了独占模式,是一个不可重入的锁
/* 这个类中的方法还可以用来控制工作线程的执行。可以中断由于空闲一直在等待任务的
/* 工作线程,而不影响已经在执行任务的工作线程(请看shutdown().interruptIdleWorkers()中的解释).
*/
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/**
* This class will never be serialized, but we provide a
* serialVersionUID to suppress a javac warning.
*/
private static final long serialVersionUID = 6138294804551838833L;
/** Thread this worker is running in. Null if factory fails. */
final Thread thread;
/** Initial task to run. Possibly null. */
Runnable firstTask;
/** Per-thread task counter */
volatile long completedTasks;
/**
* Creates with given first task and thread from ThreadFactory.
* @param firstTask the first task (null if none)
*/
Worker(Runnable firstTask) {
/**
/* 在任务开始前,防止任务被中断,
/* 因为interruptIdleWorkers方法在中
/* 断任务的时候,
/* 会先trylock()获取锁,state == -1 trylock就失败了
*/
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
/** Delegates main run loop to outer runWorker */
public void run() {
runWorker(this);
}
// Lock methods
//
// The value 0 represents the unlocked state.
// The value 1 represents the locked state.
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) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
// Worker执行任务的时候需要先获取锁
public void lock() { acquire(1); }
// 尝试获取锁,成功说明worker还未开始执行任务,state == 0,处于可以中断的状态,
// 失败说明worker已经在执行任务了state == 1,或者处于禁止中断的状态state == -1
public boolean tryLock() { return tryAcquire(1); }
// 释放锁
public void unlock() { release(1); }
// 锁是否被持有,true表示worker开始执行任务了
public boolean isLocked() { return isHeldExclusively(); }
// 如果worker可以中断(state != -1),则中断线程
void interruptIfStarted() {
Thread t;
// getState() >= 0 worker处于非禁止中断状态
// (t = thread) != null 说明ThreadFactory创建线程成功,
// ThreadFactory创建线程失败会返回null
// !t.isInterrupted()线程还没有被中断
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
我们不着急分析execute方法,因为调用链比较深,很多条件判断让人不明所以,我们现在看下shutdown
/**
/* 停止线程池,对已经运行的任务没有影响,线程池不再接受新的任务
/* 但是线程池会继续处理队列中的任务,这个方法不会等待任务执行,而是立即返回
/* 线程池状态变更为SHUTDOWN
*/
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 检查权限,无视它。。。
checkShutdownAccess();
// 更改状态为SHUTDOWN
advanceRunState(SHUTDOWN);
// 中断空闲的工作线程,空闲线程指的是一直等待任务的线程
interruptIdleWorkers();
// 空的方法,需要子类实现
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
void onShutdown() {
}
可以看到shutdown(),会将线程的状态更改为SHUTDOWN。
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}
/**
/* 中断空闲的工作线程,如果中断成功,每个线程在退出时
/* 都会传播中断信号(传播的代码在runWorker().processWorkerExit()),
/* 以便检测线程池是否可以关闭(状态rs向TERMINATED靠近,)
*/
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
/**
/* !t.isInterrupted() 线程未中断。
/* w.tryLock()成功说明w未执行任务(空闲)且处于可以中断的状态。
/*
/* runWorker()时候如果没有可以执行的任务,w会一直等待任务,此
/* 时state == 0,runWorker()在自旋执行getTask()时如果检测
/* 到中断信号就会结束等待退出线程;
/*
/* runWorker()时有可以执行的任务,会w.lock加锁,任务开始执
/* 行后就可以保证如果此时执行shutdown()尝试获取锁肯定失败,
/* 这样已经在执行的任务就不会被中断。
/* 这也是Worker类上的英文注释为啥那么bb的原因
*/
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
/**
/* 停止线程池,线程池不再接受新的任务,中断所有线程(包括空闲非空闲的)
/* java中的所谓中断,其实都是发送一个中断信号给线程,线程响应不响应这个
/* 信号没有保证,因为任务是我们编码提供的,对于正在执行中的任务所以如果需要响应中断的话,
/* 得自己编写相关代码。
/* 这个方法不会等待任务执行完,而是立即返回,因为所有线程都中断了
/* ,所以会清空任务队列并返回这些任务
/* 线程池状态变更为STOP
*/
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 检查权限,无视它。。。
checkShutdownAccess();
// 更改状态为STOP
advanceRunState(STOP);
// 中断所有可以中断的任务
interruptWorkers();
// 清空任务队列并返回这些任务
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
/**
/* 中断所有可以中断的任务,只要state != -1。
/* ,如果中断成功,每个线程在退出时都会
/* 传播中断信号(会执行runWorker().processWorkerExit().tryTerminate()),
/* 以便检测线程池是否可以关闭(状态rs向TERMINATED靠近)
/* 对于state == -1的线程是没法中断的,此时分为两种情况:
/* 1、任务队列不为空,此时线程池的状态是STOP了,这些线程监测到这个状态,会自己中断自己(看runWorker中的说明)
/* 2、任务队列为空,runWorker时工作线程会一直等待任务
/* 所以shutdownNow也是无法保证所有线程都是关闭的
/* ,这也是为啥工作线程在退出时会tryTerminate会传播中断信号的原因之一。
*/
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
/**
/* 將任务队列中的任务移入到list中并返回,同时将任务队列清空
/* 很简单,我就不多bb了
*/
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = workQueue;
ArrayList<Runnable> taskList = new ArrayList<Runnable>();
q.drainTo(taskList);
if (!q.isEmpty()) {
for (Runnable r : q.toArray(new Runnable[0])) {
if (q.remove(r))
taskList.add(r);
}
}
return taskList;
}
/**
/* 任何可能导致线程池状态走向TERMINATED的方法(满足工作线程减少)都需要执行这个方法。
/* shutdown和shutdownNow方法都是用来终止线程池的,区别在于:
/* 1、shutdown只关闭空闲线程,不会清空任务队列中的任务,同时可能还会有活跃的线程
/* 2、shutdownNow关闭了所以能关闭的线程(可能有些线程处于未关闭状态),
/* 同时任务队列会被清空
*/
final void tryTerminate() {
for (;;) {
int c = ctl.get();
/**
/* isRunning(c) 说明 rs == RUNNING; or
/* runStateAtLeast(c, TIDYING)说明rs = TIDYING/TERMINATED; or
/* (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())说明rs == SHUTDOWN 但是任务队列不为空
/* 总结下意思是满足(rs == SHUTDOWN && workQueue.isEmpty) ||
/* (rs == STOP)就往下走
/* 为啥TIDYING不能往下走呢?
/* 因为rs一到TIDYING会立即执行terminated(),执行完后状态立马更改为TERMINATED
*/
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
// wc != 0,说明可能还有线程空闲,中断一个空闲线程,以便传播中断信号
if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
/**
/* 走着这里说明
/* ((rs == SHUTDOWN && workQueue.isEmpty) || rs == STOP) &&
/* wc == 0
/* 完美满足TIDYING的条件
*/
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
// 默认是个空方法,需要子类实现
terminated();
} finally {
// rs = TERMINATED,wc =0
ctl.set(ctlOf(TERMINATED, 0));
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
// 默认实现为空
protected void terminated() { }
我们再回过头看execute方法,这时候就一路了然了。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// wc < corePoolSize
if (workerCountOf(c) < corePoolSize) {
// 创建worker执行任务
if (addWorker(command, true))
return;
// addWorker失败
c = ctl.get();
}
// 走到这里说明wc > corePoolSize
// 将任务存放在任务队列
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
// 线程池终止不再接收新的任务
if (! isRunning(recheck) && remove(command))
// 任务无法执行被拒绝
reject(command);
// wc == 0,池中没有线程了,创建任务线程执行任务队列中的任务
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 工作队列已满,创建工作线程执行任务
else if (!addWorker(command, false))
// 任务无法执行被拒绝
reject(command);
}
/**
/* 创建工作线程,并启动工作线程执行任务,工作线程会不停轮训,如果空闲,会等待任务
/* firstTask:工作线程第一个执行的任务,等于null的话,工作线程会去任务队列取任务
/* core:任务队列有界时,用来控制工作线程的最大数,是corePoolSize还是maximumPoolSize
*/
private boolean addWorker(Runnable firstTask, boolean core) {
// retry循环的作用是将判断能否添加worker,如果可以wc + 1
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
/**
/* rs >= SHUTDOWN 线程池不再接受新的任务。
/*
/* a = (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())
/* 意思是 SHUTDOWN后任务队列可能不为空,如果firstTask == null的话,允许创建
/* 一个新的worker去任务队列获取任务执行
/* (查看runWorker中的while循环就知道是啥意思了)
*/
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// addWorker没有加锁控制,并发addWorker CAS可能会失败,需要自旋
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
// rs发生变化,可能被shutdown或者晋升到shutdown以后的状态,
// 自旋转再次检查状态
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
// 创建worker并把worker存入线程池,启动worker执行任务
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());
// 1、RUNNING
// 2、SHUTDOWN, 需要去处理任务队列中的任务
// retry已经检查过一次了,这里再次判断的原因是:retry循环未加锁,执行完后rs可能改变了
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 自定义ThreadFactory的时候,不要启动线程,不然就挂了
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) {
// t的runnable是worker,t.start()调用的是worker.run(),最终调用的是runWorker
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
/**
/* 如果启动工作线程失败,需要做三件事
/* 1、从线程池移除这个工作线程
/* 2、wc--
/* 3、尝试终止线程池
/* 很简单,不多bb
*/
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
workers.remove(w);
decrementWorkerCount();
tryTerminate();
} finally {
mainLock.unlock();
}
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
// 如果w还没执行到这里,shutdownNow和shutdown的时候w就不会收到中断信号
w.unlock(); // allow interrupts
// 是否异常
boolean completedAbruptly = true;
try {
// getTask从队列中获取任务
// 如果没有任务,会一直等待任务,(rs == SHUTDOWN+)时遇到中断就退出线程
// 如果有任务,执行任务
while (task != null || (task = getTask()) != null) {
w.lock();
/**
/* STOP后不再执行任务
/* 这里的判断是为了中断那些shutdownNow后未中断的线程
/*
/* (rs >= STOP || (Thread.interrupted() && rs >= STOP))的意思是
/* 1、rs >= STOP 如果未中断就中断
/* 2、rs < STOP 清除中断信号
/*
*/
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 {
processWorkerExit(w, completedAbruptly);
}
}
runWorker中的while是执行任务的主要流程,执行流程为:
beforeExecute -> task.run -> afterExecute
子类可以重写beforeExecute 和afterExecute方法,因为afterExecute在finally代码块中所以期间产生的任何Throwable 都会传递给afterExecute
runWorker执行的任务,要么是worker.firstTask,如果该任务为null或者已经执行完,那么就会尝试从队列中获取
/**
/* 从任务队列中获取任务
/* 线程池的keepAliveTime线程空闲超时退出机制,使用队列的超时pool方法来实现
/* 线程空闲会一直尝试获取任务,如果超过keepAliveTime还未成功就退出
*/
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.
/**
/* rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty()) ==
/* 1、rs >= STOP 说明执行过shutdownNow了,任务队列肯定会空 ||
/* 2、rs >= SHUTDOWN && workQueue.isEmpty() 执行过shutdown/shutdownNow了,
/* 且任务队列已经空了
*/
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// 需要将超时线程退出
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
/**
/* wc > maximumPoolSize 说明调用了setMaximumPoolSizemaximumPoolSize,
/* 新的值比旧的值小
/* timed && timedOut 获取任务超时
/* (wc > 1 || workQueue.isEmpty()) ==
/* !(wc = 0 && !workQueue.isEmpty()) 意思是如果任务队列不是空的
/* ,起码要有一个线程来处理任务
*/
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
// wc--
// CAS失败,说明存在并发,需要自旋重新检查条件
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;
}
}
}
runWorker如果任务执行期间有任何异常都会传播给finally代码块中的processWorkerExit方法
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// 由于发送异常造成的退出
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
// 线程退出,从线程池中移除
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
// 传播中断信号,rs尝试向TERMINATED晋升
tryTerminate();
int c = ctl.get();
// rs == RUNNING or SHUTDOWN
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);
}
}
// c < s 返回true
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
// 任务被拒绝
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
线程池由于任务队列已满或者线程已达最大值都有可能拒绝任务,线程池提供了有几种策略
策略 | 说明 |
---|---|
AbortPolicy | 默认的策略,直接抛出RejectedExecutionException |
CallerRunsPolicy | 如果线程池还是RUNNING,直接由当前线程执行这个任务,这回导致线程池处理接收任务的速度变慢 |
DiscardPolicy | 直接丢弃任务 |
DiscardOldestPolicy | 如果线程池还是RUNNING,将任务队列头部的任务丢弃,再尝试提交这个任务 |
我们自己也可以实现RejectedExecutionHandler,这里不再多言。
除了execute、shutdown、shutdownNow这些线程调度方法外,线程池还提供了其它几类方法
,实现都非常简单,就不多bb了
类型 | 方法 |
---|---|
线程调度 | execute、shutdown、shutdownNow、invokeAll、invokeAny、submit、beforeExecute、afterExecute、onShutdown、awaitTermination、prestartAllCoreThreads、prestartCoreThread、purge、remove |
动态配置 | setCorePoolSize、setKeepAliveTime、setMaximumPoolSize、setThreadFactory、setThreadFactory、allowCoreThreadTimeOut |
获取配置信息 | getCorePoolSize、getKeepAliveTime、getMaximumPoolSize、getQueue、getRejectedExecutionHandler、getThreadFactory、allowsCoreThreadTimeOut |
统计 | getActiveCount、getCompletedTaskCount、getLargestPoolSize、getPoolSize、getTaskCount |
状态分析 | isShutdown、isTerminated、isTerminating |