推荐阅读资料点击这里
第一部分:
该类有以下几个构造函数:
1、public ThreadPoolExecutor(int corePoolSize,//核心线程数量
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
corePoolSize
核心线程数量,线程池刚创建的时候,线程数量为0,当每次执行execute添加新任务会在线程池中创建一个线程,直到线程数量达到corePoolSize。
maximumPoolSize
最大线程数量,当线程数量达到corePoolSize时,执行execute后会将任务添加到workQueue中,等待执行
keepAliveTime
当线程数量大于corePoolSize时,线程空闲时间超过keepAliveTime会被销毁,直到线程数量回落到corePoolSize。
unit
与keepAliveTime搭配使用,是一个时间单位,有天、小时、秒等。
workQueue
在线程数量达到corePoolSize时,后面再提交的任务存放到workQueue中进行排队,等待执行。
上面这个构造函数最终会调用另外一个构造函数
2、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;
}
前面的5个参数和第一个参数类似,现在来分析另外两个参数
threadFactory
这是一个线程工厂,用来生产线程对象,对于默认线程工厂(可以实现自己的线程工厂)来说创建对象的时候传入实现了Runnable接口的对象。下面是默认的线程工厂类:
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();//这个是系统安全管理器(有空可以去了解一下)
group = (s != null) ? s.getThreadGroup() :Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +poolNumber.getAndIncrement() + "-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,namePrefix + threadNumber.getAndIncrement(),0);
if (t.isDaemon())
t.setDaemon(false);//启动一个用户线程(不是守护线程)
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);//普通线程优先级
return t;
}
}
这个类是用来生产线程的,通过newThread函数来创建线程,里面通过传入实现Runnable接口类对象(这个对象在提交任务的时候会进行传入)。
handler
这个对象用来拒绝执行新添加的任务,抛出异常。实现接口RejectedExecutionHandler的类定义如下:
/**
* A handler for rejected tasks that throws a
* {@code RejectedExecutionException}.
*/
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
通过函数rejectedExecution抛出异常。那么什么情况下会抛出异常,后面会讲到。
3、public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
这个构造函数可以用来设置自己的线程工厂,handler采用的是默认的。
给一个例子:
ThreadPoolExecutor scheduler = new ThreadPoolExecutor(1,3,60*60,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(200),new ThreadFactory(){
@Override
public Thread newThread(Runnable r){
Thread t;
t = new Thead(r,"AsyncRequestPersistence");
return t;
);
上面在构造一个类对象scheduler时采用了自己的线程工厂。
4、public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
这个构造函数可以让用户设置自己实现RejectedExecutionHandler接口的类对象,也就是说一旦线程数量达到了最大,此时外界还在提交任务时应该如何处理这个问题。这个过程交由用户自己进行处理。
以上就是ThreadPoolExecutor类的四个构造函数。关于线程池对象关系图如下所示:
第二部分
我们开始分析任务提交函数,总共有两个提交任务的函数,一个是submit,另外一个是execute。execute是从Executor接口继承过来,而submit是从ExecutorService接口继承过来,submit函数最终都会调用execute函数。
submit
我们先来看看相关类接口之间的关系图:
可以看到FutureTask类既可以有Runnable的run功能,又有Future接口的取消、获得线程执行结果值等功能。
submit总共有三个函数
1、public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
2、public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
3、public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
我们看到不管传递的参数是Runnable实现类还是Callable实现类,返回值类型都是Future。第一个和第二个函数还好理解,唯一的区别就是参数的个数不同,那么我们来看一下第3个函数,它是如何将Callable实现类转换成Future的。首先看一下newTaskFor函数
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
FutureTask类有两个构造函数:
1、public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
2、public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
第一个构造函数会将Callable实现类对象赋值到类成员变量callable,而第二个构造函数会将Runnables实现类对象转换成Callable实现类对象,我们来看看它是怎么转换的。
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
返回的是继承了RunnableAdapter类对象,这个类的定义如下:
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}
可以看到这个类实现了接口Callable,将Runnable实现类对象赋值到task成员变量中,result同样处理了,同事实现的call()函数中执行了run函数,同时返回result值。
综上来看,不管是Callable,还是Runnable,都是汇聚成了一个Callable实现类,前者的call函数调用的是Callable实现类对象的call函数,后者call函数调用的是Runnable实现类中的run函数,同时还有返回值result。
现在进入到execute函数中
在开始分析这个函数前,我们先来了解一下线程池相关变量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;//111 可以新加线程,同时可以处理queue中的线程
private static final int SHUTDOWN = 0 << COUNT_BITS;//000 不增加新线程,但是处理queue中的线程
private static final int STOP = 1 << COUNT_BITS;//001 不增加新线程,同时不处理queue中的线程
private static final int TIDYING = 2 << COUNT_BITS;//010 所有的线程都终止了(queue中),同时workerCount为0,那么此时进入TIDYING
private static final int TERMINATED = 3 << COUNT_BITS;//011 方法结束,变为TERMINATED
// Packing and unpacking ctl
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; }
从第二行开始分析,COUNT_BITS的值为29,关于在计算机中,数字经过原码->反码->补码过程得到最终的值,计算机中存储的值是经过这些转换得来的,正数的原码、反码、补码都相同,负数则不同,例如 int 型的1的原码、反码、补码为
00000000 00000000 00000000 00000001
int型-1的原码、反码、补码为:
10000000 00000000 00000000 00000001 原码
11111111 11111111 11111111 11111110 反码
11111111 11111111 11111111 11111111 补码
根据上面的描述,CAPACITY 为1向左移动29位,变成:
00100000 00000000 00000000 00000000
前三位为001,后面29位为0,值为2^29,然后再在这个基础上减去1变成2^29-1,原码、反码、补码变成:
00011111 11111111 11111111 11111111
RUNNING为:
11100000 00000000 00000000 00000000
SHUTDOWN为:
00000000 00000000 00000000 00000000
STOP为:
00100000 00000000 00000000 00000000
TIDYING为:
01000000 00000000 00000000 00000000
TERMINATED为:
01100000 00000000 00000000 00000000
runStateOf函数中c & ~CAPACITY;就是c和11100000 00000000 00000000 00000000进行"与"操作
workerCountOf函数中c & CAPACITY;就是c和00011111 11111111 11111111 11111111进行"与"操作
ctlOf函数就是rs和wc进行"或"操作
经过上面的分析,可以得出,高三位用来记录线程池的各种状态,而其他的29位用来统计线程池中的线程数量。
好了,我们继续下面的execute函数分析:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//如果当前运行的线程数量小于核心线程数量
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))//新建一个worker
return;
c = ctl.get();
}
//如果有线程在运行,同时任务被成功提交到队列中
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))//如果不能新加线程,同时不可以处理queue中的线程,那么就移除掉command
reject(command);
else if (workerCountOf(recheck) == 0)//上下两个操作都有addWorker的操作,但是如果在workQueue.offer的时候Worker变为0,
//那么将没有Worker执行新的task,所以增加一个Worker.
addWorker(null, false);
}
//如果workQueue满了,那么这时候可能还没到线程池的maxnum,所以尝试增加一个worker
else if (!addWorker(command, false))
reject(command);//如果worker数量达到上限,那么就拒绝此线程
}
在讲addWorker前,我们先分析一下retry的使用方法。
//retry:// 1(行2)
for (int i = 0; i < 10; i++) {
retry:// 2(行4)
while (i == 5) {
break retry;
//continue retry;
}
System.out.print(i + " ");
}
retry相当于一个标记,只用在循环里面,很像goto语句,break到retry字符处。如果retry没有在循环(for,while)里面,在执行到retry时,就会跳出整个循环。如果retry在循环里面,可以理解为跳到了关键字处执行,不管几层循环。continue理解也是一样。所以下面的执行结果有以下情况:
在采用行2的retry情况下:
采用break retry:
0 1 2 3 4
采用continue retry:
0 1 2 3 4 6 7 8 9
在采用行4的retry情况下:
采用break retry:
0 1 2 3 4 5 6 7 8 9
采用continue retry:
0 1 2 3 4然后一直在while中循环
现在进入到addWorker中
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
/*从这里是可以看出一些策略的
首先,在rs>SHUTDOWN时,拒绝一切线程的增加,因为STOP是会终止所有的线程,同时移除Queue中所有的待执行的线程的,所以也不需要增加first=null的Worker了
其次,在SHUTDOWN状态时,是不能增加first!=null的Worker的,同时即使first=null,但是此时Queue为Empty也是不允许增加Worker的,SHUTDOWN下增加的Worker主要用于消耗Queue中的任务。
SHUTDOWN状态时,是不允许向workQueue中增加线程的,isRunning(c) && workQueue.offer(command) 每次在offer之前都要做状态检测,也就是线程池状态变为>=SHUTDOWN时不允许新线程进入线程池了。*/
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
//如果当前线程池中的线程数量大于等于最大容量那么返回false
//wc >= (core ? corePoolSize : maximumPoolSize))这个就要看core的值
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//采用cas方式添加线程数量,如果添加成功了那么中断retry处的for循环
if (compareAndIncrementWorkerCount(c))
break retry;
//如果添加线程数量失败了
//再次获取当前线程池信息
c = ctl.get(); // Re-read ctl
//如果当前线程池状态改变了,那么重新执行retry处的for循环
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 {
//创建Worker实例
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());
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;
}
worker加入成功后,开始启动worker,调用t.start(),这个start函数会调用Worker类对象中的run函数,
因为Worker类构造函数如下:
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
这里main创建一个Thread线程,参数传入的是Worker类型,它实现了接口Runnable。所以start函数最终调用Worker的run函数
public void run() {
runWorker(this);
}
进入到runWorker函数中
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//如果当前Worker对象中的task不为null或者从workQueue中取出任务不为null,这个任务就是Runnable对象
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
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);//线程开始执行之前执行此方法,可以实现worker未执行退出,本类中未实现
Throwable thrown = null;
try {
task.run();//调用run函数,执行Runnable中的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);//线程执行之后执行此方法,可以实现worker未执行退出,本类中未实现
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
上面我们看到work对象除了处理自己的task,还会处理workQueue中的task,等处理完自己的task后会到workQueue中认领task,这样也可以看出线程池就是指定个数的线程运行多个任务。现在我们进入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.
//如果当前线程池状态大于等于SHUTDOWN且(线程池状态大于等于STOP或者任务队列为空,那么就将当前线程池中的线 //程数量减一
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
//判断是否有等待时间,如果allowCoreThreadTimeOut为true或者当前线程池线程数量大于核心线程数,那么就认为有等 //待时间
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//如果(当前线程数量大于最大线程数量或者等待时间到时了)而且(线程数量大于1或者任务队列为空)
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;
}
}
}
下面开始分析线程池终止的函数
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//判断是否有权限shutdown线程池
checkShutdownAccess();
//将线程池状态改成SHUTDOWN
advanceRunState(SHUTDOWN);
//中断空闲worker
interruptIdleWorkers();
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;
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
我们看到interruptIdleWorkers函数会去遍历workers,在线程没有中断的情况下,w尝试获取到锁,如果获得了锁,那么就中断,也就是说评判线程是否是空闲线程的条件是:
首先,线程不处于中断状态
其次,可以获取到锁
为什么满足这两条就说明线程是处于空闲呢?我们再回到runWorker函数看看,worker在去获取任务的时候,一旦获取到任务就会对worker上锁,也就是说worker一旦拿到了锁说明就拿到了一个任务,就是处于执行任务状态,相反就处于空闲,所以如果tryLock获取到了锁,那么就说明这个worker没有在执行任务,处于空闲状态。
我们再看看shutdownNow,它跟shutdown差不多,
但是实现却很不相同。首先是设置线程池状态为STOP,前面的代码我们可以看到,是对SHUTDOWN有一些额外的判断逻辑,但是对于>=STOP,基本都是reject,STOP也是比SHUTDOWN更加严格的一种状态。此时不会有新Worker加入,所有刚执行完一个线程后去GetTask的Worker都会退出。
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//判断是否有权限shutdown线程池
checkShutdownAccess();
//将线程池状态改成STOP
advanceRunState(STOP);
//中断所有worker
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
//中断所有线程
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
//将workQueue中的任务全部删除,这样等待执行的任务也全部不执行了,全部抛弃掉,同时返回未执行的任务集合
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = workQueue;
ArrayList<Runnable> taskList = new ArrayList<Runnable>();
q.drainTo(taskList);
if (!q.isEmpty()) {
//这里q.toArray(new Runnable[0])用来告诉系统将q转成一个数组,数组的元素为Runnable类型
for (Runnable r : q.toArray(new Runnable[0])) {
if (q.remove(r))
taskList.add(r);
}
}
return taskList;
}
接下来是执行tryTerminate
final void tryTerminate() {
for (;;) {
int c = ctl.get();
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 {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated();
} finally {
ctl.set(ctlOf(TERMINATED, 0));
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
上面的代码其实很有意思有几种状态是不能转化到TIDYING的:
- RUNNING状态
- TIDYING或TERMINATED
- SHUTDOWN状态,但是workQueue不为空
也说明了两点:
1. SHUTDOWN想转化为TIDYING,需要workQueue为空,同时workerCount为0。
2. STOP转化为TIDYING,需要workerCount为0
如果满足上面的条件(一般一定时间后都会满足的),那么CAS成TIDYING,TIDYING也只是个过度状态,最终会转化为TERMINATED。