2016-04-12 2 views
2

У меня есть задание и резервное для него:Как использовать FallbackFuture для обработки TimeoutException?

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); 

На данный момент я ожидаю, что если задача не завершится в течение 50 мс, выходной результат будет обработан осенью, которая является легкой.

Но не так как я строганый, я получил следующее исключение:

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

Что заставляет меня потерять все результаты от других задач успеха. Кажется, что резерв не работал в этом случае для меня. Или я неправильно понял эту концепцию?

ответ

6

Нам нужно отличить «Future сбой» и «вызов Future.get не срабатывает».

  • «Future« не удалось », если задание, предоставленное вами, выдает исключение. (Для целей withFallback, мы также считаем отмену быть провал Это не имеет значения здесь, хотя и может измениться, когда-нибудь.).
  • «Вызов Future.get терпит неудачу», если любой из следующих случиться:
    • Future терпит неудачу
    • времен Выкрикивают
    • вызова прерывается

withFallback обрабатывает только случай, когда Future не работает, без обработки тайм-аутов или прерываний.

Если ваша цель состоит в том, чтобы получить все основные результаты, которые выполняются в течение 50 миллисекунд, со всеми другими случаями, вернуться к вторичным результатам, вы можете попробовать что-то вроде этого, который использует withTimeout автоматически проваливают 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(); 

Но обратите внимание, что это последний get вызов может ждать дольше, чем 50 миллисекунд: Если первичный Future не удается, то get вызов должен ждать, пока его запасной вариант не будет сделано. Если вы не хотите ждать резервных копий, вам также необходимо обернуть их withTimeout. И если вы их завершите, тогда они будут терпеть неудачу после таймаута, и в этом случае allAsList также потерпит неудачу. Если вы этого не хотите, вам нужно либо использовать successfulAsList (вместо allAsList), либо снова обернуть обертки withFallback, на этот раз со значением, которое всегда доступно сразу.

+0

Большое спасибо за четкое объяснение на упаковке WithFallback :) – Xitrum

Смежные вопросы