私が見たグアバの例に基づいて、私は自分の問題に対するエレガントな解決策を探してきました。具体的には、私は 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
のみを出力します。
更新:これは 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);