CompletableFuture超时后返回所有完成的结果

时间:2019-06-08 02:44:37

标签: java completable-future

我要列出我想等待的可完成期货。使用以下代码。

  public static <T> CompletableFuture<List<T>> finishAllQuery(
  List<CompletableFuture<T>> futures) {
CompletableFuture<Void> allDoneFuture =
    CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
return allDoneFuture.thenApply(
    v -> futures.stream().filter(Objects::nonNull)
        .map(future -> future.join())
        .collect(Collectors.toList())
);
  }
CompletableFuture<List<Result>> allResponse = finishAllQuery(futures);
allResponse.get(5, milliseconds)

问题是,在所有期货中,其中一些期货可能会变慢,我希望到期后,get方法返回所有已完成的结果。有办法吗?

非常感谢。

2 个答案:

答案 0 :(得分:0)

如果您不一定要完成所有期货交易,则不应使用allOf()。您可以改为使用CompletionService,然后将poll()方法与超时一起使用。因此,流程将是:

  1. 将ExcecutorService包裹在CompletionService中
  2. 将N个任务提交给CompletionService。然后使用超时轮询单个任务。像这样:

elapsedTime = 0; availableTime = 5ms; completedFutures = List();

while (elapsedTime < availableTime):
    remainingTime = availableTime - elapsedTime; 
    startTime = currentTime();
    completedFutures.add(CompletionService.poll(timeout=remainingTime));
    elapsedTime += (currentTime() - startTime)

答案 1 :(得分:0)

这应该由finishAllQuery本身来处理。例如,从Java 9开始,您可以使用

public static <T> CompletableFuture<List<T>> finishAllQuery(
    List<CompletableFuture<T>> futures, long timeOut, TimeUnit unit) {

    return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
        .completeOnTimeout(null, timeOut, unit)
        .thenApply(v -> futures.stream()
            .filter(CompletableFuture::isDone)
            .map(CompletableFuture::join)
            .collect(Collectors.toList()));
}

使用completeOnTimeout,我们可以在超时后用预定义的值强制完成将来。在这里,我们仅使用null,因为allOf的结果值无关紧要。

我们只需要添加一个过滤条件,即可跳过所有尚未完成的期货,否则,join将阻塞线程。

这可以像

一样使用
CompletableFuture<List<Result>> allResponse
    = finishAllQuery(futures, 5, TimeUnit.MILLISECONDS);
List<Result> list = allResponse.join(); // will wait at most 5 milliseconds

对于Java 8,我们可以使用

static <T> CompletableFuture<T> completeOnTimeout(
    CompletableFuture<T> cf, T value, long timeOut, TimeUnit unit) {

    ScheduledExecutorService e = Executors.newSingleThreadScheduledExecutor();
    ScheduledFuture<Boolean> job = e.schedule(() -> cf.complete(value), timeOut, unit);
    return cf.whenComplete((x,y) -> { job.cancel(false); e.shutdown(); });
}

缺少的功能,需要进行少量重写:

public static <T> CompletableFuture<List<T>> finishAllQuery(
    List<CompletableFuture<T>> futures, long timeOut, TimeUnit unit) {
    return completeOnTimeout(
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])),
        null, timeOut, unit)
        .thenApply(v -> futures.stream()
            .filter(CompletableFuture::isDone)
            .map(CompletableFuture::join)
            .collect(Collectors.toList()));
}

调用方使用方法的方式不变。

对于生产用途,值得重写completeOnTimeout方法以重用ScheduledExecutorService,但这还需要添加关闭代码或创建守护程序线程的线程工厂。使用Java 9或更高版本,您可以免费获得。