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);
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
try {
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);
}
}
这个方法是执行任意一个任务的方法
判断参数任务集合是否为空 且长度是否为0 如果为空或长度为0 就抛出异常
创建一个ArrayList对象futures 泛型为Future 将任务数放入
创建一个ExecutorCompletionService对象ecs 将本对象放入
进入try块
创建ExecutionException异常对象 初始值为空
然后确定任务截止时间 如果参数timed为true 截止时间就是当前时间加上第三个参数 如果timed为false 截止时间就是0
然后获取任务集合的迭代器
然后将第一个任务添加进futures 任务数减一 创建临时变量active为1代表活跃任务
进入无限for循环
从ecs的阻塞队列里取出第一个Future结果 赋给临时变量f
如果f为空 那么进行如下判断:
如果任务数大于0 任务数自减一 futures里添加下一个任务 active数自增
如果active数等于0 就跳出for循环
如果timed参数为true 也就是存在任务计时 从ecs的阻塞队列里按照截止时间取出一个Future结果 如果任务为空 抛出超时异常 并在截止时间中扣除已用掉的时间
上述判断都不成立 就调用ecs的take方法 直接从阻塞队列里取出一个Future结果 赋给临时变量f
为什么从ecs的阻塞队列里取Future结果呢?因为之前的博客里说了 ExecutorCompletionService有个内部类QueueingFuture 这个类有个done方法 任务执行完了 将Future结果放入外部类的阻塞队列里 这个逻辑要看子类对Executor接口的execute方法是否有相关实现 当然这个方法doInvokeAny是私有的 被包裹在invokeAny方法中 以ThreadPoolExecutor为例 在addWorker方法中
if (workerAdded) {
t.start();
workerStarted = true;
}
这里线程启动后被添加进 ExecutorCompletionService的阻塞队列中
判断如果f不为空
active数自减一
返回f的get方法 在catch块中实例化ExecutionException对象
跳出for循环后 如果ExecutionException为空 就实例化这个异常并抛出
然后循环遍历futures 挨个cancel掉其他任务
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;
}
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return doInvokeAny(tasks, true, unit.toNanos(timeout));
}
这两个方法都是调用了doInvokeAny的方法 不多说了
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);
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
try {
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);
}
}
这个方法是执行任意一个任务的方法
判断参数任务集合是否为空 且长度是否为0 如果为空或长度为0 就抛出异常
创建一个ArrayList对象futures 泛型为Future 将任务数放入
创建一个ExecutorCompletionService对象ecs 将本对象放入
进入try块
创建ExecutionException异常对象 初始值为空
然后确定任务截止时间 如果参数timed为true 截止时间就是当前时间加上第三个参数 如果timed为false 截止时间就是0
然后获取任务集合的迭代器
然后将第一个任务添加进futures 任务数减一 创建临时变量active为1代表活跃任务
进入无限for循环
从ecs的阻塞队列里取出第一个Future结果 赋给临时变量f
如果f为空 那么进行如下判断:
如果任务数大于0 任务数自减一 futures里添加下一个任务 active数自增
如果active数等于0 就跳出for循环
如果timed参数为true 也就是存在任务计时 从ecs的阻塞队列里按照截止时间取出一个Future结果 如果任务为空 抛出超时异常 并在截止时间中扣除已用掉的时间
上述判断都不成立 就调用ecs的take方法 直接从阻塞队列里取出一个Future结果 赋给临时变量f
为什么从ecs的阻塞队列里取Future结果呢?因为之前的博客里说了 ExecutorCompletionService有个内部类QueueingFuture 这个类有个done方法 任务执行完了 将Future结果放入外部类的阻塞队列里 这个逻辑要看子类对Executor接口的execute方法是否有相关实现 当然这个方法doInvokeAny是私有的 被包裹在invokeAny方法中 以ThreadPoolExecutor为例 在addWorker方法中
if (workerAdded) {
t.start();
workerStarted = true;
}
这里线程启动后被添加进 ExecutorCompletionService的阻塞队列中
判断如果f不为空
active数自减一
返回f的get方法 在catch块中实例化ExecutionException对象
跳出for循环后 如果ExecutionException为空 就实例化这个异常并抛出
然后循环遍历futures 挨个cancel掉其他任务
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;
}
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return doInvokeAny(tasks, true, unit.toNanos(timeout));
}
这两个方法都是调用了doInvokeAny的方法 不多说了