如何将DeferredResult与ListenableFuture列表结合起来?

时间:2016-11-29 16:56:03

标签: java spring-mvc guava future

我有一个Guava ListenableFuture实例列表和Spring DeferredResult列表。我想在列表中为第一个成功的未来设置结果,或者如果超时尚未到期,则从所有期货中获得成功结果。这是我的尝试:

DeferredResult<String> foo() {
    DeferredResult<String> result = new DeferredResult<>(3000L);

    List<String> resps = newArrayList();
    List<ListenableFuture<String>> fList = ...

    fList.forEach(f -> Futures.addCallback(f, new FutureCallback<String>() {
        @Override
        public void onSuccess(String resp) {
            resps.add(resp);
        }

        @Override
        public void onFailure(Throwable t) {
            // NOP
        }
    }));

    ListenableFuture<List<String>> f0 = Futures.successfulAsList(fList);

    Futures.addCallback(f0, new FutureCallback<List<String>>() {
        @Override
        public void onSuccess(List<String> r) {
            if (!result.hasResult()) {
                result.
                    if (r != null) {
                        result.setResult(...);
                    }
                }
            }

            @Override
            public void onFailure(Throwable t) {
                // NOP
            }
        }); 

    return result;  
}

我的代码不起作用,因为它等待所有期货的结果,但我需要关于DeferredResult超时的最快结果。我该如何解决?

2 个答案:

答案 0 :(得分:0)

DeferredResult<String> foo() {
  DeferredResult<String> result = new DeferredResult<>(3000L);

  List<ListenableFuture<String>> fList = ...

  ExecutorService serializingExecutor = Executors.newSingleThreadExecutor();
  fList.forEach(
      f ->
          Futures.addCallback(
              f,
              new FutureCallback<String>() {
                @Override
                public void onSuccess(String value) {
                  if (!result.hasResult()) {
                    result.setResult(value);
                  }
                }

                @Override
                public void onFailure(Throwable throwable) {}
              },
              // To avoid race in the callback:
              serializingExecutor));

  return result;
}

答案 1 :(得分:0)

这会返回包装器对象,其中包含在超时之前设法完成的Futures的结果列表,并指示是否所有已完成(allFinished属性)。

在您的处理代码中,您可以检查是否全部完成,并返回整个列表或仅返回第一个项目(如果没有未完成,则返回任何内容)。

DeferredResult<ResultWrapper> foo() {
        DeferredResult<ResultWrapper> result = new DeferredResult<>(3000L);

        ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(3));
        List<ListenableFuture<String>> fList = IntStream.range(1, 1000)
                .mapToObj(i -> executor.submit(() -> String.valueOf(i))).collect(Collectors.toList());

        List<String> resps = Lists.newArrayListWithCapacity(fList.size());
        Object lock = new Object();

        fList.forEach(f -> Futures.addCallback(f, new FutureCallback<String>() {
            @Override
            public void onSuccess(String resp) {
                synchronized (lock) {
                    resps.add(resp);
                    result.setResult(new ResultWrapper(
                            resps.size() == fList.size(), 
                            ImmutableList.copyOf(resps)));
                }

            }

            @Override
            public void onFailure(Throwable t) {
                // NOP
            }
        }));

        return result;
    }

    private static class ResultWrapper {

        private boolean allFinished;
        private List<String> list;

        public ResultWrapper(boolean allFinished, List<String> list) {
            this.allFinished = allFinished;
            this.list = list;
        }

        public boolean isAllFinished() {
            return allFinished;
        }

        public List<String> getList() {
            return list;
        }
    }