接下来我们开始研究激动人心的java并发的核心–线程池,并发包里的很多api都是服务于线程池的,像前面讲到AQS,重入锁,以及后面会讲解的阻塞队列等等,都可以在线程池的源码中看到。由于线程池设计到的api有多个,我这里就一步步来讲,先研究比较简单的AbstractExecutorService。
一、接口关系图
从以下关系图中可以看到,AbstractExecutorService作为抽象执行服务类,实现了ExecutorService接口和顶层的Executor接口。其具体的实现类是ThreadPoolExecotor,它是线程池的核心实现逻辑,后面介绍。另外AbstractExecutorService还关联了FutureTask类,FutureTask是异步返回线程执行结果的具体实现类,后面也会有专门讲解。
二、源码分析
下面简单分析AbstractExecutorServcie以及上层接口的源码
1.Executor
Executor我叫它做执行者吧,它的源码很简单就一个方法execute(),简单理解就是专门用来执行命令的,你传什么进来,我就不折不扣地执行。这里也可以看到java代码抽象的简洁之道。
public interface Executor {
execute(Runnable command);
}
2.ExecutorService
ExecutorService接口增加了很多功能方法,它作为服务接口,对外提供这些服务,实现类必须实现这些接口
public interface ExecutorService extends Executor {
// 关闭线程池,会等待正在执行中的线程执行完
void shutdown();
// 立刻关闭线程池,如果有正在执行的线程,会被中断
List<Runnable> shutdownNow();
// 判断线程池是否被关闭了
boolean isShutdown();
// 判断线程池是否终止了,这是线程池的最终状态
boolean isTerminated();
// 等待给定时间后终止线程池
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
// 提交一个执行任务,返回一个未来的引用,这个引用可以获取到执行结果
<T> Future<T> submit(Callable<T> task);
// 提交一个执行任务,返回一个未来的引用,这个引用可获取到结果是传入的参数result
<T> Future<T> submit(Runnable task, T result);
// 提交一个执行任务,返回一个未来的引用,这个引用可以获取到执行结果,入参跟Callable相比就是入参的范围比较广了,只要实现Runable接口即可
Future<?> submit(Runnable task);
// 执行所有传入的任务,等待所有任务结束才返回,结果都在返回的list里面,
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;
// 跟上面方面相比,会有一个时间限制完成所有的任务,如果时间耗尽,有些任务没执行完,则没有结果
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
// 返回任意一个执行的结果
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
// 给定时间内返回任意一个执行结果
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
3.AbstractExecutorService
AbstractExecutorService有线程池的部分实现逻辑,这里能大概看到线程池大体的实现方案,虽然不够详细,但是这里是理解线程池原理的入口。
submit提交任务
// 这个有返回的结果的提交方法,是比较容易看理解线程池原理的
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
// 这里创建了一个Future,我们理解线程执行完后会被结果放到这里
RunnableFuture<Void> ftask = newTaskFor(task, null);
// execute是执行任务的方法,可以猜测它会开启一个线程异步处理,然后把结果放到future里面
execute(ftask);
return ftask;
}
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
// 这个有传入结果入参的方法,会把result作为结果放到future里面,所以线程执行完的话,它的结果就是result了,从后面的代码可以看出它的原理
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;
}
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
// 这里使用了适配器,适配成Callable接口
return new RunnableAdapter<T>(task, result);
}
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
// 这里就是传入的result
this.result = result;
}
public T call() {
task.run();
// 这里看出调用call的话会返回刚刚传入的result
return result;
}
}
invokeAll方法解析,等待所有任务完成才返回
// 这里是执行任务集合的方法
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
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 {
// 最后判断done的值,如果为false说明发生了异常,则取消每个任务的执行,所以最终返回的结果可能是被取消了的,结果可能为null
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
invokeAny方法解析,只要有一个结果就返回
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
try {
return doInvokeAny(tasks, false, 0);
} catch (TimeoutException cannotHappen) {
assert false;
return null;
}
}
private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
boolean timed, long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
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);
// 这个类专门用来处理批量有返回的线程,线程返回的future会放到一个阻塞队列里,然后调用take方法获取,后面讲解
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
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();
// 首先执行一个任务,假如这个任务很快返回了,那么后面的任务就不用执行了
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);
}
}
三、总结
AbstractExecutorService是研究线程池原理的入口,这个抽象类中搭起了线程池的原理框架,只要把这个类理解透了,那么研究更细节的代码就会有个所以然的结果。