如何在循环中调用可完成的未来并结合所有结果?

时间:2017-10-05 15:32:19

标签: java completable-future

我正在努力实现这样的目标。这是一个表达意图的组成示例。

我希望所有可完成的期货都能执行并将所有结果合并到一个结果并返回。因此,对于下面的示例,集合allResults应该具有字符串"一个","两个","三个",每个3次。我希望它们全部并行而不是连续运行。

我可以用来实现这一目标的可用未来API的任何指针都非常有用。

public class Main {


    public static void main(String[] args) {

        int x = 3;
        List<String> allResuts;

        for (int i = 0; i < x; i++) {

           //call getCompletableFutureResult() and combine all the results
        }

    }

    public static CompletableFuture<List<String>> getCompletableFutureResult() {

        return CompletableFuture.supplyAsync(() -> getResult());
    }

    private static List<String> getResult() {


        List<String> list = new ArrayList<>();
        list.add("one");
        list.add("two");
        list.add("three");

        return list;
    }


}

2 个答案:

答案 0 :(得分:5)

Venkata Raju的答案有问题。 Raju使用 get 调用未来,这是一个阻塞调用,并且杀死了以异步方式编码的主要目的。总是避免做到期货。

有很多内置方法可以处理未来的值,比如thenApply,thenAccept,thenCompose,thenCombine等。

当你必须处理多个未来时,

CompletableFuture.allOf方法就被用来了。

它具有以下签名

public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)

旁注: CompletableFuture.anyOf可以在您只关心第一个未来完成时使用。当您需要完成所有期货时,请使用allOf

我会使用CompletableFuture.allOf以下列方式编写您的规范。

public class DorjeeTest {


    public static CompletableFuture<List<String>> getCompetableFutureResult() {
        return CompletableFuture.supplyAsync(() -> getResult());
    }
    public static List<String> getResult() {
        return Lists.newArrayList("one", "two", "three");
    }

    public static void testFutures() {
        int x = 3;
        List<CompletableFuture<List<String>>> futureResultList = Lists.newArrayList();
        for (int i = 0; i < x; i++) {
            futureResultList.add(getCompetableFutureResult());
        }

        CompletableFuture[] futureResultArray = futureResultList.toArray(new CompletableFuture[futureResultList.size()]);

        CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(futureResultArray);

        CompletableFuture<List<List<String>>> finalResults = combinedFuture
                .thenApply(voidd ->
                        futureResultList.stream()
                                .map(future -> future.join())
                        .collect(Collectors.toList()));

        finalResults.thenAccept(result -> System.out.println(result));
    }


    public static void main(String[] args) {
        testFutures();
        System.out.println("put debug break point on this line...");

    }
}

答案 1 :(得分:1)

您无法在第一个for循环中收集结果,因为这意味着您在等待上一个任务的结果时甚至没有启动其他任务。

一旦所有任务开始,就开始收集结果。

public static void main(String[] args) throws Exception
{
  int x = 3;

  Queue<CompletableFuture<List<String>>> cfs = new ArrayDeque<>(x);
  for (int i = 0; i < x; i++)
  {
    cfs.add(getCompletableFutureResult());
  }

  List<String> allResuts = new ArrayList<>();
  for (CompletableFuture<List<String>> cf : cfs)
    allResuts.addAll(cf.get());

  System.out.println(allResuts);
}