可听的未来、未来回拨和超时

2022-09-01 07:01:21

根据我看到的番石榴的例子,我一直在寻找解决我问题的优雅解决方案。具体来说,我喜欢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


答案 1

更新:这已被添加到番石榴作为Futures.withTimeout()


在内部,我们有一个方法,该方法采用 as 输入并返回一个新的,该方法将具有相同的结果,除非原始结果尚未在给定的截止日期前完成。如果截止时间过期,则输出的结果设置为 .因此,您可以调用侦听器并将其附加到输出 。makeTimeoutFutureFutureFutureFutureTimeoutExceptionmakeTimeoutFutureFuture

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)

返回一个将来库,该将来投影委托给另一个将来项,但如果指定的持续时间过期,则该将来项将提前完成(通过包装在 中)。在这种情况下,委托未来不会被取消。TimeoutExceptionExecutionException

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

答案 2

推荐