我正在使用ExecutorService.invokeAll(Callable,超时值( TimeUnit)方法
在提交给ExecutorService的每个可调用的可调用函数中,我都有一个future.get()
即使future.get()已经超时,executorService ()还会在后台运行吗?
我是否也必须在future.get( timeout,TimeUnit)上指定超时,并抛出一个TimeoutException以确保未来被终止?
发布于 2018-01-05 18:16:18
正如文献资料所说:
返回时,尚未完成的任务将被取消。
它没有明确声明,但它使用Future.cancel(true),即中断正在运行的任务。由于Future.get()支持中断,这将导致它通过抛出一个InterruptedException来完成。如果您的Callable没有捕获它,也没有任何可能重置中断状态的内容,这意味着如果指定给invokeAll的超时时间过去了,这些调用将停止在Future.get()中等待。
然而,invokeAll只取消了未来,因此,发送中断信号,而不等待线程对其作出反应,并完成Callable代码的执行。因此,到那时,由于超时,invokeAll完成了,一些线程可能仍然运行在已经取消的任务上。但是,如果这些任务只是由一个future::get组成,那么这不应该是一个问题。
但是,如果您想要做的就是等待现有Future列表的完成,那么您可以更高效地完成这个任务。毕竟,您正在将每个Future封装到一个调用Future.get的Callable中,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,为每个Callable创建了一个Future之后,等待所有未来的完成的方式。如前所述,如果您只想等待现有期货的列表,您可以通过向执行者提交作业来直接做到这一点,而不会浪费资源。使用这种方法的另一个好处是,这将取消原来的期货,而不仅仅是取消等待期货的工作。您还可以依赖此方法取消中断,而该属性没有为invokeAll显式指定,
发布于 2017-12-20 13:35:47
来自Javadoc
执行给定的任务,在所有完成或超时到期时返回保存其状态和结果的期货列表
因此,1.所有结果都将由所有Callable提供,包括内部future.get()调用的结果;2.一旦invokeAll返回(在超时之前),所有期货都将终止。
https://stackoverflow.com/questions/47907133
复制相似问题