如何使用FallbackFuture处理TimeoutException?

时间:2016-04-12 13:56:36

标签: java guava

我有我的任务和后备:

ListenableFuture<T> listenableAsyncTask = executorService.submit(asyncTaskCallable);
ListenableFuture<T> listenableFallbackTask = executorService.submit(fallBackTaskCallable);

从他们那里,我形成了一个容忍失败的ListenableFuture:

ListenableFuture<T> failTolerantListenableFuture = Futures.withFallback(listenableAsyncTask, new FutureFallback<T>() {
                @Override
                public ListenableFuture<T> create(Throwable t) throws Exception {
                    return listenableFallbackTask;
                }
            });

我有一份容忍失败的期货清单:

List<ListenableFuture<T>> listenableFutures = ...;

是时候在一定时间内得到结果了:

result = Futures.allAsList(listenableFutures).get(50,TimeUnit.MILLISECONDS);

此时,我希望如果任务未能在50ms内完成,则返回输出将由fallBackTask处理,后者是一个轻量级的。

但不是我计划的,我得到以下例外:

java.util.concurrent.TimeoutException: Timeout waiting for task.

这导致我失去了其他成功任务的所有结果。在这种情况下,对我来说,后备似乎并不起作用。或者我误解了这个概念?

1 个答案:

答案 0 :(得分:6)

我们需要区分“Future失败”和“对Future.get的调用失败。”

  • 如果您提交的任务引发异常,则“Future失败”。 (出于withFallback的目的,我们也认为取消是失败的。但是这里没有相关性,行为可能会在某一天发生变化。)
  • “如果发生以下任何,则对Future.get的调用失败”:
    • Future失败
    • 通话超时
    • 电话中断

withFallback仅处理Future失败的情况,而不处理超时或中断的情况。

如果您的目标是检索在50毫秒内完成的所有主要结果,并且所有其他情况都会回到辅助结果,您可以尝试使用withTimeout自动使{在给定的超时后{1}}:

Future

但请注意,上一次List<ListenableFuture<T>> originalFutures = ...; List<ListenableFuture<T>> defaultAfterTimeoutFutures = new ArrayList<>(); for (ListenableFuture<T> f : originalFutures) { f = Futures.withTimeout(f, 50, MILLISECONDS, executor); f = Futures.withFallback(f, ...); defaultAfterTimeoutFutures.add(f); } result = Futures.allAsList(defaultAfterTimeoutFutures).get(); 调用可能会等待超过50毫秒:如果主get失败,则Future调用必须等到其回退完成。如果您不想等待回退,那么您还需要使用get包装它们。如果你确实包装它们,那么它们将在超时后失败,此时withTimeout也将失败。如果您不希望这样,那么您需要使用allAsList(而不是successfulAsList)或再次使用allAsList包装包装器,这次使用的值始终为立即可用。