web-dev-qa-db-ja.com

ListenableFuture、FutureCallback、およびタイムアウト

私が見たグアバの例に基づいて、私は自分の問題に対するエレガントな解決策を探してきました。具体的には、私は Futures.addCallback(ListenableFuture, FutureCallback) が機能する方法が好きですが、FutureCallbackが呼び出される前に期限切れになる可能性がある時間の長さにタイムアウトを設定できるようにしたいと考えています。最適には、タイムアウトに違反すると、FutureCallbackの失敗状態が呼び出されただけでいいのです。

グアバはすでにこのようなものを持っていますか?タイムアウトとコールバックを組み合わせるのはお勧めしませんか?

編集:このポイントに私を導いたコードの例を含みます。明らかに、最小限の例を得るために、意味のある部分を取り除いた。

@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のみを出力します。

33
Nick Campion

更新:これは Futures.withTimeout() としてGuavaに追加されました。


内部的には、makeTimeoutFutureメソッドを使用してFutureを入力として受け取り、同じ結果を除いて新しいFutureを返しますオリジナルは指定された期限までに完了していません。期限が切れると、出力Futureの結果がTimeoutExceptionに設定されます。したがって、makeTimeoutFutureを呼び出して、リスナーを出力Futureにアタッチできます。

makeTimeoutFutureは、問題に対する最も自然な解決策ではありません。実際、このメソッドは主に、引数なしの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);
23
Chris Povirk