等待一批Future完成时超时了?

11

我有一组由将Callable提交给Executor创建的Futures。伪代码:

for all tasks
  futures.add(executor.submit(new callable(task)))

现在我想要获取所有等待时间最多为n秒的futures,直到全部完成。我知道我可以调用Future#get(timeout),但如果我在循环中逐个调用所有的futures,超时时间将会不断累加。 伪代码:

for all futures
  future.get(timeout)

使用带有超时的 get 方法获取块,直到结果准备就绪。 因此,如果第一个刚好在超时之前完成,第二个也正好在超时之前完成,以此类推,则整个执行时间最多为 未来数量*超时时间,而不是 超时时间
因此,我正在寻找一种接受Future列表和超时时间的方法,在并行运行所有内容后返回未来结果集合。 有什么想法吗?

这并不十分清晰。当超时到期时,您想要发生什么,对于那些未完成的任务?您想让它们被取消还是允许它们继续? - Jim Garrison
它们应该被取消。另外,我需要知道哪些已经完成了,哪些没有完成。我想我可以再次迭代所有的 futures,并在它们上面调用 isDone 方法来实现这一点。 - Marcel Stör
1个回答

12

您可以使用ExecutorService.invokeAll方法:

执行给定的任务,返回一个 Future 列表,该列表包含它们的状态和结果,当所有任务完成或超时到期时,以先完成的为准。返回列表中的每个元素的 Future.isDone() 方法都返回 true。在返回之后,未完成的任务将被取消。请注意,已经完成的任务可能是正常终止或者抛出异常终止的。如果在此操作正在进行时修改了给定的集合,则此方法的结果是未定义的。


如果您已经有需要监控的 Future 对象而无法使用 invokeAll,则可以自行测量超时时间。伪代码:

long endTime = System.currentTimeMillis() + timeoutMS;
for(f : futures)
    f.get(Math.max(0, endTime - System.currentTimeMillis()), TimeUnit.MILLISECONDS);

这样做可以确保每个未来得到的时间不会超过达到超时之前剩余的时间。


“ExecutorService.invokeAll”听起来像是我需要的,谢谢。对于所有在规定时间内未完成的future,“isCancelled==true”,对吗(这是我如何解释Javadoc的)?如果一个Future完成时出现异常,我该怎么办?“请注意,已完成的任务可能是正常终止或通过抛出异常终止”的说明很困难... - Marcel Stör
1
@MarcelStör 是的,未完成的 futures 会被取消(isCancelled() == true)。当你调用 Futureget() 方法时(在 invokeAll 返回后),你可以确定 Future 发生了什么。如果 get 抛出 CancellationException,则说明它已被取消。如果它抛出 ExecutionException,则意味着 Future 已经完成并且带有异常,异常可以通过 ExecutionException.getCause() 访问。 - Petr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接