我有我的任务和后备:
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.
这导致我失去了其他成功任务的所有结果。在这种情况下,对我来说,后备似乎并不起作用。或者我误解了这个概念?
答案 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
包装包装器,这次使用的值始终为立即可用。