CompleteableFuture Java 8异常行为

时间:2019-07-03 03:22:07

标签: java

我注意到Java 8中带有Streaming的CompleteableFutures有一些异常行为。

String [] arr = new String[]{"abc", "def", "cde", "ghj"};
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        List<String> lst =
                Arrays.stream(arr)
                        .map(r ->
                                CompletableFuture.supplyAsync(() -> {
                                    try {
                                        Thread.sleep(5000);
                                        return "e";
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                    return null;
                                }, executorService)
                        )
                        .map(CompletableFuture::join)
                        .collect(Collectors.toList());

上面的这段代码需要4 * 5000 = 20秒的时间来执行,因此这意味着期货正在彼此等待。

 String [] arr = new String[]{"abc", "def", "cde", "ghj"};
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        List<CompletableFuture<String>> lst =
                Arrays.stream(arr)
                        .map(r ->
                                CompletableFuture.supplyAsync(() -> {
                                    try {
                                        Thread.sleep(5000);
                                        return "d";
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                    return null;
                                }, executorService)
                        )
                        .collect(Collectors.toList());

        List<String> s =
                lst
                        .stream()
                        .map(CompletableFuture::join)
                        .collect(Collectors.toList());

        System.out.println(s);

但是此代码会在5秒钟内运行,这意味着期货正在并行运行。

我不了解的地方:在第二个示例中,我明确获取了一份期货列表,然后进行了连接,这需要5秒钟,第一个示例中,我一直在进行跟踪,似乎等待。

这背后的原因是什么?

1 个答案:

答案 0 :(得分:1)

流不一定要先执行一个阶段,然后再执行下一个阶段。他们可以按照选择的任何顺序进行操作。

例如,

Arrays.stream(array).map(e -> f(e)).map(e -> g(e)).collect(toList());

最终可能会以与

相同的方式运行
Arrays.stream(array).map(e -> g(f(e))).collect(toList());

...您将看到结果:一次生成一个期货并立即将其加入,而不是先生成所有期货再将其加入。

事实上,如果您不执行异步操作,则第二种方法通常效率更高。这样,流框架不必存储f的所有结果,而是存储g的所有结果:它只能存储g(f(e))的结果。流框架不知道您正在执行异步代码,因此它可以执行正常的高效操作。