【问题标题】:CompletableFuture not working as accepted with certain java 8 stream codeCompletableFuture 无法与某些 java 8 流代码一样工作
【发布时间】:2020-05-09 18:52:12
【问题描述】:

我关注this SO answer

下面的代码 sn-p 工作得很好。使用所有线程

片段 1

scrolledPage.stream()
    .filter(this::isUserDoesntHaveId)
    .map(this::processSingle)                                          // processSingle method return supplier
    .map(task -> CompletableFuture.supplyAsync(task, executorService)) // map to CompletableFuture
    .collect(Collectors.toList())                                      // Collect those as list
    .stream()                                                          // then again making another stream out of that.
    .map(CompletableFuture::join)
    .filter(Objects::nonNull)
    .collect(Collectors.toList());

我对这段代码感到困惑

    .map(task -> CompletableFuture.supplyAsync(task, executorService)) // map to CompletableFuture
    .collect(Collectors.toList())                                      // Collect those as list
    .stream()                                                          // then again making another stream out of that.
    .map(CompletableFuture::join)

为什么我需要收集然后再次制作它。我已经测试过如下。

片段 2

scrolledPage.stream()
    .filter(this::isUserDoesntHaveId)
    .map(this::processSingle)                                           // processSingle method return supplier
    .map(task -> CompletableFuture.supplyAsync(task, executorService)) // map to CompletableFuture
    .map(CompletableFuture::join)               // this code is similar without the collecting part.
    .filter(Objects::nonNull)
    .collect(Collectors.toList());

使用我看到的最后一个代码 sn-p 只使用线程池中的一个线程。但是第一个使用每个线程。这两个代码sn-ps有什么区别。

【问题讨论】:

    标签: java java-8 completable-future


    【解决方案1】:

    第一个 sn-p 可以分为两部分。 在第一部分中,您使用 CompletableFuture 将所有任务提交到异步进程,并且当它立即返回 Future 对象时,流将处理并收集列表中的所有未来。

    List<Future> futures = scrolledPage.stream()
        ...
        .map(task -> CompletableFuture.supplyAsync(task, executorService))
        .collect(Collectors.toList())
    

    稍后,流处理将在您使用join 时等待结果,但届时所有线程都将开始工作。因此它能够利用所有线程。

        futures.stream()
           .map(CompletableFuture::join)
           ...
           .collect(Collectors.toList());
    

    Streams 进行惰性求值意味着它只会在需要时处理元素。 (需求由终端操作触发,本例为collect)。

    在第二个 sn-p 中,map(CompletableFuture::join) 让线程在处理流中的下一个元素之前等待结果

    .stream()
    ...
    .map(task -> CompletableFuture.supplyAsync(task, executorService))
    .map(CompletableFuture::join)
    ...
    .collect(Collectors.toList())
    

    因此,您在流中的任务(下一个元素)只有在第一个任务完成时才会被处理。这将使您的任务一个接一个地按顺序执行。

    【讨论】:

    • 在第二个sn-p中,这不是map(task -&gt; CompletableFuture.supplyAsync(task, executorService))提交所有的任务和映射到future并发送到下游加入吗?其实我没看懂你的这句话。 make thread to wait for the result before processing the next element in the stream.
    • @seal 它不会提交所有任务,而是会在第一个 sn-p 中一个一个提交。流触发评估为惰性。例如,假设你的终端操作是先查找,不需要处理其他元素。当您的连接方法在中间步骤中等待结果时,处理将变为顺序。
    • 您可以在此处查看终端/中间操作等流操作。 docs.oracle.com/javase/8/docs/api/java/util/stream/…
    猜你喜欢
    • 2017-05-14
    • 1970-01-01
    • 2016-03-11
    • 1970-01-01
    • 2015-02-27
    • 2017-06-09
    • 1970-01-01
    • 2015-02-20
    • 2020-11-27
    相关资源
    最近更新 更多