线程池的核心类ThreadPoolExecutor:
线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法。每个 ThreadPoolExecutor 还维护着一些基本的统计数据,如完成的任务数。
ThreadPoolExecutor继承了AbstractExecutorService,提供四个构造方法,但最终都是调用一个构造方法来创建对象:
/**
* @param corePoolSize 线程池核心线程数量
* @param maximumPoolSize 线程池最大线程数量
* @param keepAliveTime 当活跃线程数大于核心线程数时,空闲的多余线程最大存活时间
* @param unit keepAliveTime存活时间的单位
* @param workQueue 存放任务的队列
* @param threadFactory 用ThreadFactory创建线程,默认用deaufltThreadFactory创建线程
* @param handler 超出线程范围和队列容量的任务的处理程序
*
*/
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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
AbstractExecutorService中的一些方法如submit等,并没有在ThreadPoolExecutor中重写,而是直接使用父类中的方法,在后续的介绍中会慢慢介绍。
ThreadPoolExecutor实现线程池源码解析:
ThreadPoolExecutor中定义的一些变量和常量信息:
线程状态:
//存储所有有效线程的数量和各个线程的状态信息,低29位存线程数,高3位存runState,
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 线程池状态runState,共有五种
//线程池正常运行,可以接受新的任务并处理队列中的任务;
private static final int RUNNING = -1 << COUNT_BITS;
//不再接受新的任务,但是会执行队列中的任务;
private static final int SHUTDOWN = 0 << COUNT_BITS;
//不再接受新任务,不处理队列中的任务
private static final int STOP = 1 << COUNT_BITS;
//所有的任务都已经停止,workerCount为0,执行terminate()方法
private static final int TIDYING = 2 << COUNT_BITS;
//terminated()方法执行完成
private static final int TERMINATED = 3 << COUNT_BITS;
线程状态以及状态之间的转换:
- Running,线程池创建并初始化时,线程池处于RUNNING状态;
- Running ——> Shutdown,调用 shutdown()方法;
- Running /shutdown ——> Stop,调用shotdownNow()方法;
- shutdown ——> Tidying, 队列和线程池都为空;
- Stop ——> Tidying, 当线程池为空;
- Tidying——> Terminated,terminated()完成。
ctl变量时整个类的核心,AtomicInteger保证了变量操作的原子性,下面看一下atl如何存储和获取线程状态和工作线程数的:
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
//二进制数为:00011111111111111111111111111111
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
//获取线程状态,取出runState的值(取反,按位与)
private static int runStateOf(int c) { return c & ~CAPACITY; }
//获取工作线程数,取出workerCount的值(按位与)
private static int workerCountOf(int c) { return c & CAPACITY; }
//将runState和workerCount存到同一个int中(按位或)
private static int ctlOf(int rs, int wc) { return rs | wc; }
线程池属性信息字段:
//任务队列
private final BlockingQueue<Runnable> workQueue;
//线程池的主要状态锁,对线程池状态(比如线程池大小、runState等)的改变都要使用这个锁
private final ReentrantLock mainLock = new ReentrantLock();
//存放工作集
private final HashSet<Worker> workers = new HashSet<Worker>();
//在mainLock下访问的最大线程数
private int largestPoolSize;
//核心线程数
private volatile int corePoolSize;
//最大线程数
private volatile int maximumPoolSize;
//已执行完任务数
private long completedTaskCount;
//用来创建线程的线程工厂
private volatile ThreadFactory threadFactory;
//任务拒绝策略
private volatile RejectedExecutionHandler handler;
//线程空闲存活时间
private volatile long keepAliveTime;
//是否允许核心线程设置存活时间
private volatile boolean allowCoreThreadTimeOut;
//等待终止的条件
private final Condition termination = mainLock.newCondition();
//默认使用的拒绝策略
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
//设置运行时权限
private static final RuntimePermission shutdownPerm = new RuntimePermission("modifyThread");
ThreadPoolExecutor中定义的五个内部类:
Worker:
private final class Worker extends AbstractQueuedSynchronizer implements Runnable
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) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
runWorker(this);
}
//是否持有锁,0未持有锁,1尺有所
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;
}
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) {
}
}
}
}
ThreadPoolExecutor的属性变量中定义了一个存放工作集的变量worker:
- private final HashSet<Worker> workers = new HashSet<Worker>(); //任务队列
任务队列中存放的是Worker类型的数据,而Worker实现了Runnable接口,所以Worker是一个线程类。Worker还继承了AbstractQueuedSynchronizer类,以简化获取和释放每个任务执行周围的锁,可以防止中断。Worker主要维护运行任务的线程的中断控制状态,以及其他次要的记帐功能。实现互斥锁主要目的是为了中断的时候判断线程是在空闲还是运行。这里不用ReentrantLock是为了避免任务执行的代码中修改线程池的变量。
关于AbstractQueueSynchronized:提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架。该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础。使用的方法是继承,子类通过继承同步器并需要实现它的方法来管理其状态,管理的方式就是通过类似acquire和release的方式来操纵状态。
Worker中重写的run方法中调用的事runWorker()方法:runWorker()是第一次启动执行初始化进来的任务firstTask,然后会从workQueue中获取任务执行。
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true; //是否异常,执行任务抛异常或被中断,则为true
try {
while (task != null || (task = getTask()) != null) {
w.lock();
// 如果池停止,确保线程被中断;否则确保线程未被中断
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);
}
}
拒绝策略内部类:
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
//在调用者的线程中执行任务r,除非执行器已关闭(在这种情况下,任务将被丢弃)。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
//系统默认的拒绝策略
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
//抛出异常:RejectedExecutionException.
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(); //removeFirst
e.execute(r);
}
}
}
如果缓冲队列workQueue已满,且线程池数量达到最大maximumPoolSize,线程池会使用handler指定的拒绝策略处理新添加的任务。处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize、handler执行的任务处理器。
ThreadPoolExecutor中的方法:
//常用方法
void execute(Runnable command)
在将来某个时间执行给定任务。
void shutdown()
按过去执行已提交任务的顺序发起一个有序的关闭,但是不接受新任务。
List<Runnable> shutdownNow()
尝试停止所有的活动执行任务、暂停等待任务的处理,并返回等待执行的任务列表。
boolean isShutdown()
如果此执行程序已关闭,则返回 true。
boolean isTerminated()
如果关闭后所有任务都已完成,则返回 true。
boolean isTerminating()
如果此执行程序处于在 shutdown 或 shutdownNow 之后正在终止但尚未完全终止的过程中,则返回 true。
//获取/设置常用属性信息
int getActiveCount()
返回主动执行任务的近似线程数。
long getCompletedTaskCount()
返回已完成执行的近似任务总数。
int getCorePoolSize()
返回核心线程数。
long getKeepAliveTime(TimeUnit unit)
返回线程保持活动的时间,该时间就是超过核心池大小的线程可以在终止前保持空闲的时间值。
int getLargestPoolSize()
返回曾经同时位于池中的最大线程数。
int getMaximumPoolSize()
返回允许的最大线程数。
int getPoolSize()
返回池中的当前线程数。
BlockingQueue<Runnable> getQueue()
返回此执行程序使用的任务队列。
RejectedExecutionHandler getRejectedExecutionHandler()
返回用于未执行任务的当前处理程序。
long getTaskCount()
返回曾计划执行的近似任务总数。
ThreadFactory getThreadFactory()
返回用于创建新线程的线程工厂。
void setCorePoolSize(int corePoolSize)
设置核心线程数。
void setKeepAliveTime(long time, TimeUnit unit)
设置线程在终止前可以保持空闲的时间限制。
void setMaximumPoolSize(int maximumPoolSize)
设置允许的最大线程数。
void setRejectedExecutionHandler(RejectedExecutionHandler handler)
设置用于未执行任务的新处理程序。
void setThreadFactory(ThreadFactory threadFactory)
设置用于创建新线程的线程工厂。
//不常用方法
void allowCoreThreadTimeOut(boolean value)
如果在保持活动时间内没有任务到达,新任务到达时正在替换(如果需要),则设置控制核心线程是超时还是终止的策略。
boolean allowsCoreThreadTimeOut()
如果此池允许核心线程超时和终止,如果在 keepAlive 时间内没有任务到达,新任务到达时正在替换(如果需要),则返回 true。
boolean awaitTermination(long timeout, TimeUnit unit)
请求关闭、发生超时或者当前线程中断,无论哪一个首先发生之后,都将导致阻塞,直到所有任务完成执行。
int prestartAllCoreThreads()
启动所有核心线程,使其处于等待工作的空闲状态。
boolean prestartCoreThread()
启动核心线程,使其处于等待工作的空闲状态。
void purge()
尝试从工作队列移除所有已取消的 Future 任务。
boolean remove(Runnable task)
从执行程序的内部队列中移除此任务(如果存在),从而如果尚未开始,则其不再运行。
execute()方法:
execute
方法主要三个步骤:
- 活动线程小于corePoolSize的时候创建新的线程;
- 活动线程大于corePoolSize时都是先加入到任务队列当中;
- 任务队列满了再去启动新的线程,如果线程数达到最大值就拒绝任务。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//活动线程数 < coorPoolSize
if (workerCountOf(c) < corePoolSize) {
// 启动新线程,第二个参数true:addWorker中会检查workerCount是否小于corePoolSize
if (addWorker(command, true))
//添加成功则返回
return;
c = ctl.get();
}
//活动线程数 >= corePoolSize, runState 为Running && 队列未满
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
//非Running状态,则从workeQueue中移除任务并拒绝
if (! isRunning(recheck) && remove(command))
reject(command);//拒绝,拒绝策略
// 线程池处于RUNNING状态 || 线程池处于非RUNNING状态但是任务移除失败
else if (workerCountOf(recheck) == 0)
// 这行代码是为了SHUTDOWN状态下没有活动线程了,但是队列里还有任务没执行这种特殊情况。
// 添加一个null任务是因为SHUTDOWN状态下,线程池不再接受新任务
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
可以看到execute方法中,addWorker方法出现了三次,下面主要来看一下addWorker():
//是否可以根据当前池状态和给定的界限(核心或最大值)添加新worker
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false; //返回false,线程创建失败
//线程池状态为Running,或状态为ShunDown,但队列中还有要执行的任务
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c)) //递增workCount
break retry; //返回到retry标记,跳出循环
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs) //若线程池状态发生变化,重试
continue retry;
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
final ReentrantLock mainLock = this.mainLock;
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
mainLock.lock(); //并发访问线程池woekers对象加锁
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int c = ctl.get();
int rs = runStateOf(c);
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive())
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;
}
shutdown:
shutdown这个方法会将runState置为SHUTDOWN
,并终止所有空闲的线程。
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN); //线程池状态设为SHUTDOWN,若已经至少是这个状态则直接返回
//中断所有空闲的线程:runWorker中等待的线程被中断 → 进入processWorkerExit
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
//保证队列中剩余的任务得到执行
tryTerminate();
}
shutdownNow:
shutdownNow方法将runState置为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;
}
shutdown 和 shutdownNow的主要区别是:shutdown将runState置为SHUTDOWN
,并终止所有空闲的线程;而shutdownNow将runState置为STOP,并终止所有的线程。从二者的源码中可以看到,shutdown调用的是interruptIdleWorker方法,而shutdownNow调用的是interruptIfStarted方法:
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
// w.tryLock能获取到锁,说明该线程没有在运行,因为runWorker中执行任务会先lock,
// 因此保证了中断的肯定是空闲的线程。
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
//内部类Worker的方法
void interruptIfStarted() {
Thread t;
//初始化时state == -1
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
这就是前面提到的Woker类实现AQS的主要作用.