根据 Guava 的例子,我看到了我一直在寻找解决问题的优雅方法。具体来说,我喜欢 Futures.addCallback(ListenableFuture, FutureCallback)
的工作方式,但是我希望能够对调用FutureCallback之前可以到期的时间长度设置超时。最佳的情况是,如果违反超时只是导致调用FutureCallback的失败条件。
Guava 已经有这样的东西了吗?是否只是不建议尝试将超时与回调耦合在一起?
编辑:包括导致我到这一点的代码示例。显然,我去除了有意义的部分以得到一个最小的例子。
@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
不是您问题的最自然解决方案。实际上,我认为该方法主要是为了对no-arg get()
调用设置硬超时而创建的,因为将所需的截止日期传播给所有调用者可能很痛苦。一个更自然的解决方案是,将get()
视为get(long, TimeUnit)
,将addCallback(ListenableFuture, FutureCallback)
归为addCallback(ListenableFuture, FutureCallback, long, TimeUnit, SchededuledExecutorService)
。有点笨拙,尽管比makeTimeoutFuture
少。在要做任何事情之前,我想再三考虑一下。你会file a feature request吗?
(这是我们内部拥有的:)
public static <V> ListenableFuture<V> makeTimeoutFuture(
ListenableFuture<V> delegate,
Duration duration,
ScheduledExecutorService scheduledExecutor)
返回一个委托(delegate)给另一个人的 future ,但如果指定的持续时间到期,则将提前完成(通过包裹在
TimeoutException
中的ExecutionException
)。在这种情况下不会取消委托(delegate)的将来。scheduledExecutor.schedule(new Runnable() {
@Override public void run() {
TimeoutFuture.this.setException(new TimeoutException("Future timed out"));
}
}, duration.getMillis(), TimeUnit.MILLISECONDS);