简介
刚学习线程的时候,一般都是通过Thread类(包括Runable和Callable接口)来创建的。Thread类是线程的基础,平时写个demo可以这样用,但是日常工作中几乎不可能会直接用它来创建线程,主要有以下几个原因:
-
每创建一个线程的时候都要经历创建、使用、销毁的操作,对于频繁创建线程的任务来说加大了系统的开销。
-
创建线程都需要经历以上三步,性能稍微有点点影响。
-
直接通过Thread创建线程没有节制,容易导致系统资源的耗尽。
线程池的作用
为解决上述创建单个线程的操作所带来的问题,线程池便应运而生了。顾名思义,线程池类比一个拥有一定数量的线程的集合,当一个任务需要用到线程时,从这个集合中获取,用完再还回来,以此实现了线程的复用。因此,线程池的作用正好与Thread的缺点相反:
- 降低资源消耗:复用已创建好的线程,避免重复创建和销毁线程的开销。
- 提高响应速度:复用线程省去了创建的过程,提高了响应速度。
- 线程集中管理:通过把线程集中管理起来,可以实现线程的监控和调优。
继承体系

Executor内部只有一个execute()方法,作为任务执行的顶层接口。
ExecutorService也是一个接口,继承于Executor,它提供了管理任务以及跟踪异步任务调度的方法接口。常用方法如下:
//关闭服务,先前提交的任务继续执行,但后续不再接受新任务
void shutdown();
//关闭服务,尝试停止正在执行的任务,停止所有等待执行的任务并返回等待执行任务的列表
List<Runnable> shutdownNow();
//判断服务是否已停止
boolean isShutdown();
//只有调用shutdown或者shutdownNow并且所有任务执行完成才返回true
boolean isTerminated();
//只有调用shutdown或者shutdownNow并且所有任务执行完成才返回true 否则超时返回false
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
//提交Callable任务-自带返回值
<T> Future<T> submit(Callable<T> task);
//提交Runnable任务-返回值result就是Future的get方法返回值
<T> Future<T> submit(Runnable task, T result);
//提交Runnable任务
Future<?> submit(Runnable task);
//所有任务执行完毕后,按序返回Future对象
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
//所有任务执行完毕或者执行超时后,按序返回Future对象,超时任务返回的Future对象的isDone方法为True.
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
//返回第一个执行成功的任务的Future对象,其余未执行完的任务将被取消
<T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;
//返回第一个执行成功的任务的Future对象,其余未执行完的任务将被取消。若超时后还没一个对象返回则抛出TimeoutException异常
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
AbstractExecutorService是ExecutorService接口的一个抽象实现类。主要提供了ExecutorService接口中部分方法的具体实现。
ThreadPoolExecutor是线程池的核心管理类。功能强大,也是今天的主角。
属性
/*
线程池控制状态,包含两部分信息:
runState-线程池的运行状态-前3位表示
workerCount线程池内有效线程的数量-后29位表示
*/
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 线程池线程数量占用位数-29位
private static final int COUNT_BITS = Integer.SIZE - 3;
// 线程池线程数量--2^29-1
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
/* 线程池运行状态类别 */
// 运行状态,允许接受新的任务,并同时处理阻塞任务
private static final int RUNNING = -1 << COUNT_BITS;
// 调用shutdown方法后进入该状态 表示不再接受新任务,但会处理完阻塞队列的任务。
private static final int SHUTDOWN = 0 << COUNT_BITS;
// 调用shutdownnow方法进入该状态,表示不再接受新任务,也不处理阻塞队列的任务,同时中断正在处理的任务
private static final int STOP = 1 << COUNT_BITS;
// 如果所有的任务都已终止了,有效线程数为0,线程池进入该状态后会调用 terminated() 方法进入TERMINATED 状态。
private static final int TIDYING = 2 << COUNT_BITS;
// 在terminated() 方法执行完后进入该状态
private static final int TERMINATED = 3 << COUNT_BITS;
// 获取运行状态
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 final BlockingQueue<Runnable> workQueue;
// 主锁-用于获取workers时加锁
private final ReentrantLock mainLock = new ReentrantLock();
// 包含线程池中的所有工作线程,只有在获取到mainLock的情况下才能访问,Worker集合
private final HashSet<Worker> workers = new HashSet<Worker>();
// 等待条件
private final Condition termination = mainLock.newCondition();
// 跟踪线程池最大容量,仅在获取到mainLock锁下才能获取,该属性只是用来记录线程池达到的最大线程数量
private int largestPoolSize;
// 完成任务的计数器,仅在终止工作线程时更新,仅在mainLock下访问。
private long completedTaskCount;
// 线程工厂,用于创建线程
private volatile ThreadFactory threadFactory;
// 当任务饱和或者调用shutdown时调用该处理操作
private volatile RejectedExecutionHandler handler;
// 当线程数超过核心线程数量corePoolSize,并且空闲时间超过该值的空闲线程会被终止
private volatile long keepAliveTime;
// 是否允许核心线程超时,默认false,表示核心线程一直存活
private volatile boolean allowCoreThreadTimeOut;
// 核心线程数量
private volatile int corePoolSize;
// 最大线程数量
private volatile int maximumPoolSize;
// 默认拒绝策略(任务饱和或调用shutdown)-其实是抛出RejectedExecutionException异常
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
构造方法
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;
}
内部类Worker
Worker可以看做是一个工作者,它将任务绑定到指定的线程上,实现一个任务单元的处理。线程池中有个工作者集合workers存放着所有正在执行的工作者;
private final class Worker extends AbstractQueuedSynchronizer implements Runnable
{
private static final long serialVersionUID = 6138294804551838833L;
// 当前工作者的工作线程
final Thread thread;
// 工作任务
Runnable firstTask;
// 线程任务计数器
volatile long completedTasks;
// 创建工作者
Worker(Runnable firstTask) {
// 在runWorker之前禁止中断
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
// 调用外部的执行方法
runWorker(this);
}
// 重写AQS的是否获取到锁的方法 返回0表示到解锁,1表示已锁定
protected boolean isHeldExclusively() {
return getState() != 0;
}
// 重写AQS的尝试获取锁方法
protected boolean tryAcquire(int unused) {
// 原子方式获取锁
if (compareAndSetState(0, 1)) {
// 获取锁成功后设置当前线程为独占线程
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// 重写AQS的释放锁方法
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(); }
// 如果线程启动了,则启动中断
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
常用方法
execute()
该执行任务的方法主要分为三个步骤:
- 如果当前线程数量小于核心线程数量并且当前线程池处于正常运行状态,则尝试创建一个新的线程来处理任务。
- 将任务加入到工作队列中,并再次检查是否应该增加线程或者将任务从工作队列剔除(因为可能之前的检查存在的线程超时停止了或者线程池状态在此时变成了SHUTDOWN状态);
- 如果任务加入失败,则再次尝试新增工作线程。若再次新增工作线程失败,说明线程池处于非正常运行 或者 工作线程数量已经饱和,此时执行拒绝策略;
public void execute(Runnable command) {
// 执行操作为空抛出异常
if (command == null)
throw new NullPointerException();
// 获取当前的线程池控制状态(线程池状态和线程数量)
int c = ctl.get();
// 当前线程数量小于核心线程数量
if (workerCountOf(c) < corePoolSize) {
// 新增工作线程来执行该任务
if (addWorker(command, true))
return;
// 重新获取到当前ctl值
c = ctl.get();
}
// 能走到这里说明有效线程已经大于核心线程了
// 如果线程池正常运行 并且尝试将任务放入工作队列
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
// 再次检查线程池状态,如果线程池非正常运行则将任务从工作队列取出
if (! isRunning(recheck) && remove(command))
// 执行拒绝策略
reject(command);
// 再次检查工作线程是否都超时停止了
else if (workerCountOf(recheck) == 0)
// 若此时无工作线程,则新增工作线程
addWorker(null, false);
}
// 执行到此处说明线程池处于非正常运行或者工作队列满了,此时尝试新增工作线程
else if (!addWorker(command, false))
// 再次新增工作线程失败有两个原因:线程池处于非正常运行 或者 工作线程已达到最大数量,此时执行拒绝策略
reject(command);
}
addWorker()
该方法主要作用是新增工作线程并执行传入的任务,如果线程池数量已经达到饱和则直接返回false。主要步骤为(正常情况,异常情况则直接返回或回滚操作):
- 原子更新工作线程数量加1;
- 创建工作线程对象worker,绑定指定任务和线程池工厂创建线程;
- 将新工作线程对象加入到工作线程列表中统一管理;
- 启动线程;
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
// 这里循环主要作用是为完成工作线程数量的原子性增加
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
/**
* 检查是否立即返回false,包括以下5种情况:
* 1).rs为RUNNING,通过校验。
* 2).rs为STOP或TIDYING或TERMINATED,返回false。
* (STOP、TIDYING、TERMINATED:已经停止进入最后清理终止,不接受任务不处理队列任务)
* 3).rs为SHUTDOWN,提交的任务不为空,返回false。
* (SHUTDOWN:不接受任务但是处理队列任务,因此任务不为空返回false)
* 4).rs为SHUTDOWN,提交的任务为空,并且工作队列为空,返回false。
* (状态为SHUTDOWN、提交的任务为空、工作队列为空,则线程池有资格关闭,直接返回false)
* 5).rs为SHUTDOWN,提交的任务为空,并且工作队列不为空,通过校验。
* (因为SHUTDOWN状态下刚好可以处理队列任务)
*/
if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()))
return false;
// 此处循环主要作用是完成工作线程数量的原子更新
for (;;) {
int wc = workerCountOf(c);
// 工作线程数量超过最大容量 或超过核心线程(execute时) 或线程池最大线程数量时返回false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 原子更新工作线程数量
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
// 如果线程池状态发生改变了则从头开始执行
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 {
// 创建一个新工作线程并绑定当前任务
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());
// 线程池为RUNNING 或者 (线程池为SHUTDOWN 且 任务为空)时继续
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 预检查线程是可用的
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.start();
workerStarted = true;
}
}
} finally {
// 如果线程启动失败则回滚之前的操作
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
// 线程新增失败回滚操作
private void addWorkerFailed(Worker w) {
// 同样采用加锁的方式
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
// 从工作线程列表中移除工作线程
workers.remove(w);
// 原子更新工作线程数量
decrementWorkerCount();
// 如果是最后一个线程退出可能要关闭线程池
tryTerminate();
} finally {
mainLock.unlock();
}
}
runWorker()
该方法属于工作线程run方法执行的方法,它主要有两个任务:
- 处理创建时交给它的任务;
- 上步完成后再循环从任务队列中获取一个任务处理;
final void runWorker(Worker w) {
// 获取当前线程
Thread wt = Thread.currentThread();
// 取出工作线程初始的任务
Runnable task = w.firstTask;
// 将当前任务置为空,
w.firstTask = null;
// 给当前工作线程解锁
w.unlock(); // allow interrupts
// 线程因为异常而退出标识
boolean completedAbruptly = true;
try {
// 先处理当前任务,之后从任务队列中取任务执行
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
// 如果线程池停止,确保线程中断,否则确保线程不被中断。在第二种情况下进行重新检查,以便在清除中断的同时处理shutdownNow竞争
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;
// 完成任务数量加1
w.completedTasks++;
// 解锁
w.unlock();
}
}
// 如果能执行到此处,说明以上执行没有发生异常,worker是非异常退出(正常退出)
completedAbruptly = false;
} finally {
// 任务执行后退出处理
processWorkerExit(w, completedAbruptly);
}
}
getTask()
该方法主要任务是从任务队列中获取任务。取任务时有两种获取方式:
- 超时会返回null的poll()方法
- 超时会一直阻塞知道取到数据的take()方法
而选择哪种方法取决于以下两个条件之一:
- allowCoreThreadTimeOut(即允许核心线程超时,表示线程池所有线程都要采用超时返回方法)
- 当前线程超过核心线程数条件(表示核心线程会一直阻塞等待任务)
private Runnable getTask() {
// poll()方法获取任务是否超时标识
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
// 获取线程池状态
int c = ctl.get();
int rs = runStateOf(c);
// 线程池为停止状态 或者 工作队列为空时, 将workerCount减1
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
// 获取工作线程数
int wc = workerCountOf(c);
// 判断工作线程是否需要删除标识: 允许工作线程超时标识 或 当前线程数量超过核心线程数量 为true
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 若当前线程数超过最大线程数 或者 当前线程允许超时并且超时了
// 并且当前线程数大于1 或者 工作队列为空时返回null,在runWork中会进行移除Worker操作
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
// 原子更新工作线程数量
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 根据是否支持超时处理 使用相应的方法
// poll()方法有超时时间,而take()方法没有超时限制,若任务为空时会一直阻塞知道取到任务
Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();
if (r != null)
return r;
// 执行到此处说明取任务超时了
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
processWorkerExit()
该方法主要的任务是处理工作线程的退出工作,主要包含以下几个步骤:
- 如果工作线程因为异常退出需要将将当前的worker从工作者列表移除;
- 线程退出是判断是否是最后一个退出线程,是的话需要判断终止线程池;
- 如果当前工作线程因为异常退出或者本次退出的工作线程是最后一个线程同时任务队列不为空时,新增一个工作线程;
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// 如果runWorker因为异常退出时,则将工作线程数量减1
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
// 加锁同步移除worker
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
// 有线程退出时,都要判断下是否最后一个线程退出进而判断是否需要终止线程池
tryTerminate();
int c = ctl.get();
// 如果线程池还没有停止
if (runStateLessThan(c, STOP)) {
// 如果Worker是正常退出
if (!completedAbruptly) {
// 获取线程池允许存在的线程池数
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
// 如果min为0 并且工作队列不为空 则设置min为1 保证有一个工作线程来处理队列里的任务
if (min == 0 && ! workQueue.isEmpty())
min = 1;
// 如果当前工作线程大于min,则直接返回
if (workerCountOf(c) >= min)
return; // replacement not needed
// 如果走到此处,说明当前线程是最后一个工作线程
}
// 如果当前工作线程因为异常退出 或者 本次退出的工作线程是最后一个线程同时任务队列不为空时,新增一个工作线程
addWorker(null, false);
}
}
tryTerminate()
该方法用来尝试停止线程池,前提是满足以下条件:
- 线程池状态为STOP
- 线程池状态为SHUTDOWN并且工作队列为空
- 线程池中没有一个有效工作线程
final void tryTerminate() {
for (;;) {
int c = ctl.get();
// 只有当前状态为STOP 或者 SHUTDOWN并且队列为空,才会尝试整理并终止
// 1: 当前状态为RUNNING,则不尝试终止,直接返回
// 2: 当前状态为TIDYING或TERMINATED,代表有其他线程正在执行终止,直接返回
// 3: 当前状态为SHUTDOWN 并且 workQueue不为空,则不尝试终止,直接返回
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 {
// 更新线程池状态为TIDYING,并将有效线程数量置为0
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
// 停止方法-默认为空,需重写
terminated();
} finally {
// 将线程池状态置为TERMINATED,并将有效线程数量置为0
ctl.set(ctlOf(TERMINATED, 0));
// 发送消息通知
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
shutdown()
该方法主要用来停止线程池,它允许工作线程处理完阻塞的任务,但是不再接收新任务。
public void shutdown() {
// 加锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 检查是否可以停止 安全策略校验
checkShutdownAccess();
// 将线程池状态置为SHUTDOWN
advanceRunState(SHUTDOWN);
// 中断空闲线程
interruptIdleWorkers();
// ScheduledThreadPoolExecutor的钩子
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
// 尝试停止
tryTerminate();
}
shutdownNow()
该方法也是用来停止线程池,但是要求停止所有的工作线程,不管空闲还是执行中的,并将未完成的任务返回。
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;
}
总结
到此为止,基本把线程池核心类ThreadPoolExecutor的原理和核心方法介绍完了。但是线程池内在的博大精深还是需要反复琢磨的,里面包含了很多的设计思想也是非常值得学习和借鉴的。
