Подтвердить что ты не робот

ListenableFuture, FutureCallback и тайм-ауты

Основываясь на примерах guava, я видел, что искал элегантные решения моей проблемы. В частности, мне нравится способ Futures.addCallback(ListenableFuture, FutureCallback), но я хотел бы иметь возможность установить тайм-аут на время, которое может истечет до вызова функции FutureCallback. Оптимально Было бы неплохо, если бы нарушение таймаута просто вызвало отказ в вызове FutureCallback.

Есть ли у Гувы что-то подобное? Разве не рекомендуется пытаться сочетать тайм-ауты с обратными вызовами?

EDIT: Включая пример кода, который привел меня к этому моменту. Очевидно, я удалил значащие биты, чтобы получить минимальный пример.

@Test
public void testFuture()
{
    Callable<Boolean> callable = new Callable<Boolean>()
    {

        @Override
        public Boolean call() throws Exception
        {
            while(true);
        }
    };

    ListenableFuture<Boolean> callableFuture = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()).submit(callable);

    Futures.addCallback(callableFuture, new FutureCallback<Boolean>()
    {

        @Override
        public void onFailure(Throwable arg0)
        {
            System.out.println("onFailure:"+arg0); 
        }

        @Override
        public void onSuccess(Boolean arg0)
        {
            System.out.println("onSuccess:"+arg0);
        }
    }); 

    try
    {
        callableFuture.get(1000, TimeUnit.MILLISECONDS);
    }catch(Throwable t)
    {
        System.out.println("catch:"+t);
    }
}

Этот код будет печатать только catch:java.util.concurrent.TimeoutException.

4b9b3361

Ответ 1

Обновление: Это добавлено в Guava как Futures.withTimeout().


Внутри мы имеем метод makeTimeoutFuture, который принимает Future как входной сигнал и возвращает новый Future, который будет иметь тот же результат, если оригинал не будет завершен в заданный крайний срок. Если истечет срок действия, выход Future имеет свой результат, равный a TimeoutException. Таким образом, вы можете вызвать makeTimeoutFuture и подключить слушателей к выходу Future.

makeTimeoutFuture не является самым естественным решением вашей проблемы. На самом деле, я думаю, что метод был создан в основном для установки жесткого тайм-аута на вызовы no-arg get(), так как это может быть болью для распространения желаемого крайнего срока для всех вызывающих абонентов. Более естественным решением является обоснование того, что get() соответствует get(long, TimeUnit), поскольку addCallback(ListenableFuture, FutureCallback) соответствует addCallback(ListenableFuture, FutureCallback, long, TimeUnit, SchededuledExecutorService). Это немного неуклюжий, хотя и менее, чем makeTimeoutFuture. Я хотел бы дать эту мысль, прежде чем совершить что-либо. Вы файл запроса функции?

(Здесь мы имеем внутри:)

public static <V> ListenableFuture<V> makeTimeoutFuture(
    ListenableFuture<V> delegate,
    Duration duration,
    ScheduledExecutorService scheduledExecutor)

Возвращает будущее, которое делегирует другому, но заканчивается раньше (через TimeoutException, завернутый в ExecutionException), если истечет указанная продолжительность. В этом случае будущее делегата не отменяется.

scheduledExecutor.schedule(new Runnable() {
  @Override public void run() {
    TimeoutFuture.this.setException(new TimeoutException("Future timed out"));
  }
}, duration.getMillis(), TimeUnit.MILLISECONDS);