我正在使用 ExecutorService.invokeAll(Callable,timeout,TimeUnit)方法
在提交给ExecutorService的每个Callable中,我有一个 future.get()
即使executorService超时, future.get()仍会在后台运行吗?
我是否必须在 future.get(timeout,TimeUnit)上指定超时并抛出 TimeoutException 以确保将来终止?
答案 0 :(得分:1)
正如the documentation所述:
返回后,未完成的任务将被取消。
没有明确说明,但它使用Future.cancel(true)
,即中断正在运行的任务。由于Future.get()
支持中断,因此可以通过抛出InterruptedException
来完成此操作。如果您的Callable
没有捕获它,也没有做任何可能重置中断状态的事情,这意味着如果指定给Future.get()
的超时已经过去,则invokeAll
中的callables将停止等待。
然而,invokeAll
仅取消期货,因此,发送中断信号但不等待线程对其做出反应并完成Callable
代码的执行。因此,当invokeAll
由于超时而完成时,某些线程可能仍然在已经取消的任务上运行。但如果这些任务仅由future::get
组成,那么这应该不是问题。
但是如果你想要做的就是等待现有Future
列表的完成,你可以更有效率地做到这一点。毕竟,您将每个Future
包装到Callable
调用Future.get
中,invokeAll
将包装到另一个Future
中,可能会阻止每个未来的一个工作线程,然后等待所有这些未来的完成。最后一步正是这项任务的内容,所以你可以在没有前面步骤的情况下完成,例如
public static void waitForAll(Collection<? extends Future<?>> futures,
long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
boolean done = false;
try {
final long deadline = System.nanoTime() + nanos;
final int size = futures.size();
for(Future<?> f: futures) {
if(!f.isDone()) {
if (nanos <= 0L) return;
try { f.get(nanos, TimeUnit.NANOSECONDS); }
catch(CancellationException | ExecutionException ignore) {}
catch(TimeoutException toe) { return; }
nanos = deadline - System.nanoTime();
}
}
done = true;
}
finally { if (!done) for(Future<?> f: futures) f.cancel(true); }
}
这基本上是AbstractExecutorService
在提交所有Callable
之后等待所有期货完成的方式,为每个期货创建Future
。如上所述,如果您想要做的就是等待现有的期货清单,您可以直接执行此操作而不会通过向执行人员提交工作来浪费资源。使用这种方法的另一个好处是,这将取消原始期货,而不仅仅是取消等待期货的工作。您也可以依赖此方法中断取消,而invokeAll
未明确指定此属性,
答案 1 :(得分:0)
来自Javadoc
执行给定的任务,在完成或超时到期时返回持有其状态和结果的Futures列表
所以1.所有结果都将由所有Callable
提供,包括内部future.get()
调用的结果,以及2.一旦invokeAll返回(在超时之前),所有结果都是期货将会终止。