Java 8 如何在连锁的未来展开? 我想链一个完整的未来,使它在处理过程中被淘汰。我的意思是,我对一个列表有一个开放的、可完成的未来,我想对列表中的每一项进行计算

Java 8 如何在连锁的未来展开? 我想链一个完整的未来,使它在处理过程中被淘汰。我的意思是,我对一个列表有一个开放的、可完成的未来,我想对列表中的每一项进行计算,java-8,parallel-processing,completable-future,Java 8,Parallel Processing,Completable Future,第一步是调用发出异步调用的m_myApi.getResponse(请求,执行器) 该异步调用的结果有一个getCandidates方法。我想并行分析所有这些候选者 目前,我的代码以串行方式解析它们 public CompletableFuture<List<DOMAIN_OBJECT>> parseAllCandidates(@Nonnull final REQUEST request, @Nonnull final Executor executor) {

第一步是调用发出异步调用的m_myApi.getResponse(请求,执行器)

该异步调用的结果有一个getCandidates方法。我想并行分析所有这些候选者

目前,我的代码以串行方式解析它们

public CompletableFuture<List<DOMAIN_OBJECT>> parseAllCandidates(@Nonnull final REQUEST request, @Nonnull final Executor executor)
{
        CompletableFuture<RESPONSE> candidates = m_myApi.getResponse(request, executor);
        return candidates.thenApplyAsync(response -> response.getCandidates()
                                                   .stream()
                                                   .map(MyParser::ParseCandidates)
                                                   .collect(Collectors.toList()));
}
public CompletableFuture parseAllCandidates(@Nonnull final REQUEST REQUEST,@Nonnull final Executor Executor)
{
CompletableFuture候选者=m_myApi.getResponse(请求,执行者);
返回候选者。然后应用程序同步(response->response.getCandidates()
.stream()
.map(MyParser::Parse候选者)
.collect(Collectors.toList());
}
我想要这样的东西:

public CompletableFuture<List<DOMAIN_OBJECT>> parseAllCandidates(@Nonnull final REQUEST request, @Nonnull final Executor executor)
{
        CompletableFuture<RESPONSE> candidates = m_myApi.getResponse(request, executor);
        return candidates.thenApplyAsync(response -> response.getCandidates()
                                                   .stream()
                                                   .PARSE_IN_PARALLEL_USING_EXECUTOR
}
public CompletableFuture parseAllCandidates(@Nonnull final REQUEST REQUEST,@Nonnull final Executor Executor)
{
CompletableFuture候选者=m_myApi.getResponse(请求,执行者);
返回候选者。然后应用程序同步(response->response.getCandidates()
.stream()
.使用\u执行器在\u并行\u中解析\u
}

已经有一个版本的
thenApply
执行器
作为附加参数

<U> CompletionStage<U>  thenApplyAsync​(Function<? super T,​? extends U> fn, Executor executor)
CompletionStage然后应用同步​(函数如中所述,如果执行器
恰好是一个Fork/Join池,则有一个(未记录的)特性,即在其工作线程之一中启动并行流将使用该执行器执行并行操作

当您想要支持任意
Executor
实现时,事情就更复杂了

public CompletableFuture<List<DOMAIN_OBJECT>> parseAllCandidates(
       @Nonnull final REQUEST request, @Nonnull final Executor executor)
{
    CompletableFuture<RESPONSE> candidates = m_myApi.getResponse(request, executor);
    return candidates.thenComposeAsync(
        response -> {
            List<CompletableFuture<DOMAIN_OBJECT>> list = response.getCandidates()
                .stream()
                .map(CompletableFuture::completedFuture)
                .map(f -> f.thenApplyAsync(MyParser::ParseCandidates, executor))
                .collect(Collectors.toList());
            return CompletableFuture.allOf(list.toArray(new CompletableFuture<?>[0]))
                .thenApplyAsync(x ->
                    list.stream().map(CompletableFuture::join).collect(Collectors.toList()),
                    executor);
        },
        executor);
}
public CompletableFuture parseall候选者(
@非空最终请求请求,@Nonnull final Executor Executor)
{
CompletableFuture候选者=m_myApi.getResponse(请求,执行者);
返回候选者。然后重新同步(
答复->{
List=response.getCandidates()
.stream()
.map(CompletableFuture::completedFuture)
.map(f->f.thenappyasync(MyParser::ParseCandidates,executor))
.collect(Collectors.toList());
返回CompletableFuture.allOf(list.toArray(新的CompletableFuture[0]))
.然后应用同步(x->
list.stream().map(CompletableFuture::join).collect(Collectors.toList()),
执行人);
},
执行人);
}
第一个关键点是,我们必须在开始等待任何作业之前提交所有可能的异步作业,以实现执行器可能支持的最大并行性。因此,我们必须在第一步中收集
列表中的所有未来

在第二步中,我们可以迭代列表并加入所有未来。如果执行器是一个Fork/join池,并且未来尚未完成,它将检测到这一点并启动一个补偿线程以恢复配置的并行性。但是,对于任意执行器,我们不能假设这样的特性。最值得注意的是,如果xecutor是单线程执行器,这可能导致死锁

因此,该解决方案使用
CompletableFuture.allOf
仅当所有期货都已完成时才执行迭代和加入所有期货的操作。因此,该解决方案不会阻塞执行器的线程,使其与任何
执行器
实现兼容