AbstractExecutorService是一个抽象类,他实现了ExecutorSerivice接口,拿出上一篇的图:
对接口中的方法进行了实现!但是是抽象的类,无法实例化!
我们再看看他的子类可以实例化的一个类,ThreadPoolExecutor (extends AbstractExecutorService)他继承了AbstractExecutorService,其实 ThreadPoolExecutor才是线程池的真正实现,他通过构造方法的一系列参数,来构成不同配置的线程池;我们本章重点是看AbstractExecutorService:
其实我们看源代码会发现 AbstractExecutorService实现了ExecutorService接口,实现了submit等等方法,仍把execute方法留待子类实现。也就是说该抽象类AbstractExecutorService中并未对execute进行实现,也就是任务具体执行留给了子类;
1、提交任务(submit):
提交任务:创建任务(任务分2种),执行任务,返回任务;
在这里我先简单说明下Callable和Runnable主要区别:(后面章节具体介绍着2种方法使用)
(1)、Callable的call()方法可以有返回值,而Runnable接口run方法中没有;
(2)、Callable的call()方法可以声明抛异常,Runnable接口run中不可以声明抛异常
任务创建是有状态的,当newTaskFor的时候,任务的状态state = NEW;
执行任务:execute(task);说到执行任务,我们就会想到线程,因为任务肯定是在某个线程下才能去执行完成,而这里的这个线程就是子类中创建的线程池中的线程,有可能是线程池中已经存在的线程也可能是线程池中新创建的线程;
掉回头我们想一想,既然任务由线程去执行,那我提交任务submit这个操作是由哪个线程去执行的呢?在这里我们可以想象有一个业务主线程,他创建了线程池,然后有创建了任务,并把任务提交到了线程池;我们在看看真正执行execute(task)的方法具体实现在AbstractExecutorService子类中,所以这个submit()的方法他不是阻塞的,他是线程异步的一个实现;并且返回了任务的future;
2、invokeAny ()源码解析:
invokeAny取得第一个方法的返回值,当第一个任务结束后,会调用interrupt方法中断其它任务;
invokeAny最终是通过doInvokeAny实现的;
我们看doInvokeAny()源代码
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);
/**
通过构造函数,构造一个线程池服务类,其中属性中抽象了一个AbstractExecutorService服务,
和一个阻塞的队列,这个阻塞的队列completionQueue,是线程池中已经完成的任务done会被添加
到这个队列中;
*/
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
// For efficiency, especially in executors with limited
// parallelism, check to see if previously submitted tasks are
// done before submitting more of them. This interleaving
// plus the exception mechanics account for messiness of main
// loop.
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();
// Start one task for sure; the rest incrementally
//提交任务
futures.add(ecs.submit(it.next()));
--ntasks;
int active = 1;
//无限循环
for (;;) {
//取出已经完成的任务
Future<T> f = ecs.poll();
//如果没有已经完成的任务
if (f == null) {
//并且除去已经提交的任务只玩剩余的任务数量是大于0的
if (ntasks > 0) {
--ntasks;
//继续提交一个任务到线程池中
futures.add(ecs.submit(it.next()));
++active;//已经激活的任务数量加一
}
//如果激活的任务数量为0,说明提交的任务全部已经完成了,就跳出死循环
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();//从队列中获取已经完成的任务,并一直等待到获取不为null
}
if (f != null) {
--active;//如果不为null,即有任务完成,则激活的任务数量-1
try {
return f.get();//返回future结果
} 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);
}
}
上面字太小了,我还是复制下来吧:
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);
/**通过构造函数,构造一个线程池服务类,其中属性中抽象了一个AbstractExecutorService服务,
和一个阻塞的队列,这个阻塞的队列completionQueue,是线程池中已经完成的任务done会被添加
到这个队列中;
*/
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
// For efficiency, especially in executors with limited
// parallelism, check to see if previously submitted tasks are
// done before submitting more of them. This interleaving
// plus the exception mechanics account for messiness of main
// loop.
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();
// Start one task for sure; the rest incrementally
提交任务
futures.add(ecs.submit(it.next()));
--ntasks;
int active = 1;
//无限循环
for (;;) {
//取出已经完成的任务
Future<T> f = ecs.poll();
//如果没有已经完成的任务
if (f == null) {
//并且除去已经提交的任务只玩剩余的任务数量是大于0的
if (ntasks > 0) {
--ntasks;
//继续提交一个任务到线程池中
futures.add(ecs.submit(it.next()));
++active;//已经激活的任务数量加一
}
//如果激活的任务数量为0,说明提交的任务全部已经完成了,就跳出死循环
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();//从队列中获取已经完成的任务,并一直等待到获取不为null
}
if (f != null) {
--active;//如果不为null,即有任务完成,则激活的任务数量-1
try {
return f.get();//返回future结果
} 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);
}
}
通过源代码我们发现一个服务类:ExecutorCompletionService,他就是主角,这个服务类他实现了一个接口,
并且引用了Executor接口和AbstractExecutorSerivice抽象类服务;具体源码的内部逻辑分析我见上面的代码中汉语解释;
看了汉语注释是不是立刻就懂了该方法的原理实现了!哈哈
3、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 {
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
这个方法源码我就不解释了,很简单,只是他是要求全部完成任务,自己去理解源码吧!太晚了我得睡觉了。。。。