Java线程池ThreadPoolExecutor源码解析(一)
JDK提供了线程池的简单创建方式,通过Executors提供的API可以创建出不同类型的线程池,例如
// 创建一个单线程的线程池;
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
System.out.println("TEST EXECUTOR");
});
一、这里需要引入几个问题
- 构成线程池的要素?
- 线程池中的线程如何工作?
二、线程池的构造
2.1、线程池包装
当点进Executors.newSingleThreadExecutor()中可以看到下面代码
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
上面代码为构建一个ThreadPoolExecutor, 同时将构建好的ThreadPoolExecutor作为参数传递进FinalizableDelegatedExecutorService对象中,这里应用到了装饰者模式,仅仅通过FinalizableDelegatedExecutorService对ThreadPoolExecutor进行一层包装,代码如下
static class FinalizableDelegatedExecutorService
extends DelegatedExecutorService {
FinalizableDelegatedExecutorService(ExecutorService executor) {
super(executor);
}
protected void finalize() {
super.shutdown();
}
}
实际上FinalizableDelegatedExecutorService仅仅只是将ThreadPoolExecutor传递给DelegatedExecutorService,除此之外仅仅只是重写Object.finalize方法去调用ExecutorService.shutdown,而DelegatedExecutorService只是对ThreadPoolExecutor进行包装,目的只是为暴露出ExecutorService中的方法(exposes only the ExecutorService methods),当执行ExecutorService的方法时,实际上执行的是ThreadPoolExecutor的方法,代码如下
/**
* A wrapper class that exposes only the ExecutorService methods
* of an ExecutorService implementation.
*/
static class DelegatedExecutorService extends AbstractExecutorService {
private final ExecutorService e;
DelegatedExecutorService(ExecutorService executor) { e = executor; }
public void execute(Runnable command) { e.execute(command); }
public void shutdown() { e.shutdown(); }
// 省略N多代码.....
}
OK,讲到这里,实际上我们已经明确,当我们通过Executors.newSingleThreadExecutor构建出来的ExecutorService,实际上是去构建ThreadPoolExecutor,那么下面将分析下ThreadPoolExecutor是如何构建的,以及个构造参数的含义
2.2、ThreadPoolExecutor构造参数
从Executors.newSingleThreadExecutor一直往下跟,可以看到ThreadPoolExecutor构造方法如下
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,BlockingQueue
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
这里涉及的几个参数含义如下
- corePoolSize:核心线程的数量,线程池中的线程分为核心线程和非核心线程
- maximumPoolSize:线程池最大的线程数量,线程池不能无节制的创建线程,这里起到一个限制作用
- keepAliveTime:空闲线程保持时间值,与TimeUnit结合使用
- TimeUnit:时间单位,与keepAliveTime结合使用
- BlockingQueue:任务队列,一般线程池执行任务时,如果任务数大于线程数,会将任务放入队列进行等待
- ThreadFactory:生产线程的工厂,线程池是通过ThreadFactory构建线程并工作的
- RejectedExecutionHandler:拒绝策略,当线程池无法执行任务时,会走对应的拒绝策略,JDK默认提供了4种,分别为(AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy、DiscardPolicy),具体作用后续细说
2.3、ThreadPoolExecutor中的任务队列(BlockingQueue)
同样在Executors.newSingleThreadExecutor代码中可以看出,ThreadPoolExecutor中使用的是LinkedBlockingQueue作为任务队列,这是基于AQS机制实现的一种线程安全的容器,内部采用单向链表的存储结构,遵循FIFO,后续讲解其实现机制,这里简单说明下在实际使用中会应用到的方法
- BlockingQueue.offer:向队列中存放元素,线程池内部放入的是任务(Runnable)
- BlockingQueue.take:向队列获取元素,如果队列没有元素,会阻塞线程,直至队列存在元素
- BlockingQueue.poll:同take作用,但poll设置了超时机制,如果规定时间内无法从队列中获取元素,则返回NULL
以上是LinkedBlockingQueue对BlockingQueue中的offer、take和poll方法的实现,由于内容较多,后续针对LinkedBlockingQueue的源码进行单独解析
2.4、ThreadPoolExecutor中的线程工厂(ThreadFactory)
在ThreadPoolExecutor构造方法中,如果没有指明对应的ThreadFactory,默认情况下会用过Executors.defaultThreadFactory构建一个简单的线程工厂(DefaultThreadFactory),其代码如下
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中为构建好的线程附上一个名字,内部依旧是通过new Thread的方式去创建线程
线程池的构造到这里就差不多结束了,还有部分细节尚未提到,建议有兴趣的朋友可以去跟源代码,走一遍线程池的构造
三、线程池的工作原理
3.1、submit和execute区别
当需要通过线程池来执行任务时,通常可以选择调用submit和execute,二者区别在于submit可以传入Callable或者Runnable,而execute中传入的是Runnable,实际上submit内部只是对Callable或者Runnable进行封装,最终还是调用了execute,代码如下
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
可以看出,无论submit传入的是Callable或者Runnable,最终都会通过newTaskFor封装为一个FutureTask,调用execute并返回给调用者,而调用者一旦执行了FutureTask.get则会等待结果的返回
3.2、execute方法详解
通常线程池在通过execute执行任务时会经过下列几个判断
- 判断线程池当前线程数是否小于核心线程数,如果小于,则开启核心线程去运行任务
- 在不满足条件1的情况下,尝试将任务放入队列中,如果放入成功还会进行重校验,逻辑如下
2.1. 当任务放入成功后会再次校验线程池的状态,如果线程池非RUNNING状态,即放入任务期间,线程池关闭了,则会尝试将任务从队列移除,并走拒绝策略
2.2. 如果2.1判断未通过,且重校验的线程数等于0,则开启一个非核心线程,去任务队列中获取并执行任务 - 如果条件1和2都不满足的情况下,即不小于核心线程数,队列也无法容纳新元素,此时会尝试开启一个非核心线程去执行任务,如果执行失败,则通过reject走预先设定的拒绝策略;
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 通过workerCountOf获取当前线程数,判断当前线程数是否小于核心线程数,如果小于核心线程数,则调用addWorker去执行任务;
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 如果线程池当前线程数已经不小于核心线程数,就会尝试把任务放入队列中,放入成功的与否取决于offer是否执行成功,即队列仍有空间容纳元素;
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);
}
// 如果上述两个判断都无法通过,即不小于核心线程数,队列也无法容纳新元素,此时会尝试开启一个非核心线程去执行任务,如果执行失败,则通过reject走预先设定的拒绝策略;
else if (!addWorker(command, false))
reject(command);
}
3.3、addWorker方法
从execute中可以看出,线程池会通过addWorker方法去执行任务,addWorker方法会对任务进行封装,将Runnable封装为一个Worker,同时将Worker放入线程集合workers中,如果放入成功,则执行Thread.start开启线程执行任务,实际上执行的是Worker的run方法,部分关键代码如下
private final HashSet<Worker> workers = new HashSet<Worker>();
private boolean addWorker(Runnable firstTask, boolean core) {
// 此处省略部分代码.....
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());
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结构如下
- 通过ThreadFactory获取Thread,并赋值给thread属性
- 实现Runnable重写run方法,调用内部runWorker
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
// 省略部分代码......
final Thread thread;
Runnable firstTask;
volatile long completedTasks;
Worker(Runnable firstTask) {
setState(-1);
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
runWorker(this);
}
}
3.4 runWorker让线程反复执行任务
runWorker执行任务原理如下
- runWorker方法内部会开启一个while循环,不断地通过getTask方法去任务队列中获取任务
- 如果队列中依旧存在任务,执行beforeExecute方法,此方法是扩展方法,默认无任何处理
- 执行task.run,task对象是一开始放入队列中的Runnable
- 在finally中执行afterExecute,默认同beforeExecute一样
- 为Worker的completedTasks计数,记录Worker执行过的任务数
- 当任务队列清空后,执行processWorkerExit,清除线程
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock();
boolean completedAbruptly = 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);
}
}