Java CompletableFuture join()调用挂起主线程。个人的未来永远不会完成

Java CompletableFuture join()调用挂起主线程。个人的未来永远不会完成,java,completable-future,Java,Completable Future,我正在编写一个函数,创建多(7)个CompletableFutures。这些期货基本上都有两件事: 使用SupplySync(),从某些数据库获取数据 使用Accept()将此数据写入CSV文件 当所有7个futures都完成任务后,我想继续执行进一步的代码。因此,我使用allOf()并对allOf()返回的Void CompletableFuture调用一个join() 问题是,即使在执行了所有futures(我可以看到CSV正在生成)之后,join()调用仍然被卡住,进一步的代码执行将永远被

我正在编写一个函数,创建多(7)个CompletableFutures。这些期货基本上都有两件事:

  • 使用SupplySync(),从某些数据库获取数据
  • 使用Accept()将此数据写入CSV文件
  • 当所有7个futures都完成任务后,我想继续执行进一步的代码。因此,我使用allOf()并对allOf()返回的Void CompletableFuture调用一个join()

    问题是,即使在执行了所有futures(我可以看到CSV正在生成)之后,join()调用仍然被卡住,进一步的代码执行将永远被阻止

    我试过以下几件事:

  • 一个接一个地等待每个未来,在每个未来之后调用join()。这是可行的,但要以并发性为代价。我不想这样做

  • 尝试使用带有超时的get()而不是join()。但是,这总是会抛出一个异常(因为get总是超时),这是不受欢迎的

  • 已看到此JDK错误:。不确定这是否是一个类似的问题

  • 尝试在没有join()或get()的情况下运行,这将无法保持线程执行,并且再次尝试是不可取的

  • 创建所有未来的主要功能

    公共客户响应流程(){
    CustomResponse msgResponse=新CustomResponse();
    试一试{
    //1.数据库调用1
    CompletableFuture f1=dataHelper.fetchAndUploadCSV1();
    //2.DbCall 2
    CompletableFuture f2=dataHelper.fetchAndUploadCSV2();
    //3.DbCall 3
    CompletableFuture f3=dataHelper.fetchAndUploadCSV3();
    //4.DbCall 4
    CompletableFuture f4=dataHelper.fetchAndUploadCSV4();
    //5.DbCall 5
    CompletableFuture f5=dataHelper.fetchAndUploadCSV5();
    //6.DB6
    CompletableFuture f6=dataHelper.fetchAndUploadCSV6();
    //7.DB7
    CompletableFuture f7=dataHelper.fetchAndUploadCSV7();
    CompletableFuture[]fAll=新的CompletableFuture[]{f1、f2、f3、f4、f5、f6、f7};
    CompletableFuture.allOf(fAll.join();
    msgressponse.setProcessed(true);
    msgressponse.setMessageStatus(“消息”);
    }捕获(例外e){
    msgressponse.setMessageStatus(错误);
    msgressponse.setErrorMessage(“错误”);
    }
    返回msgResponse;
    }
    
    每个fetchAndUploadCSV()函数如下所示:

    public CompletableFuture fetchAndUploadCSV1(){
    返回CompletableFuture.SupplySync(()->{
    试一试{
    返回someService().getAllData1();
    }捕获(例外e){
    抛出新的运行时异常(e);
    }
    })。然后接受(结果->{
    试一试{
    如果(results.size()>0){
    上传ASCSV(结果);
    }
    否则{
    log.info(“未找到任何数据”);
    }
    }捕获(例外e){
    抛出新的运行时异常(e);
    }
    });
    }
    
    这就是
    csvWriter.uploadAsCsv(结果)
    的样子-

    public void uploadAsCsv(List objectList)引发异常{
    long objListSize=((objectList==null)?0:objectList.size();
    log.info(“Action=Start,objectListSize=“+objListSize”);
    ByteArrayInputStream inputStream=getCsvAsInputStream(对象列表);
    Info fileInfo=someClient.uploadFile(inputStream);
    log.info(“Action=Done,FileInfo=“+((FileInfo==null?null:FileInfo.getID())));
    }
    
    我在这里使用OpenCSV将数据转换为CSV流。我总能看到最后一行日志

    预期成果: 获取的所有数据、生成的CSV和CustomResponse都应返回为已处理状态,且无错误消息

    实际结果:
    获取所有数据、生成CSV并挂起主线程。

    您可以对每个已创建的
    CompletableFuture
    使用
    join
    ,而不牺牲并发性:

    public CustomResponse process() {
        CustomResponse msgResponse = new CustomResponse();
    
        List<CompletableFuture<Void>> futures = Arrays.asList(dataHelper.fetchAndUploadCSV1(),
                dataHelper.fetchAndUploadCSV2(),
                dataHelper.fetchAndUploadCSV3(),
                dataHelper.fetchAndUploadCSV4(),
                dataHelper.fetchAndUploadCSV5(),
                dataHelper.fetchAndUploadCSV6(),
                dataHelper.fetchAndUploadCSV7());
    
        return CompletableFuture.allOf(futures.toArray(new CompletableFuture<?>[0]))
                .thenApply(v -> {
                    msgResponse.setProcessed(true);
                    msgResponse.setMessageStatus("message");
                    return msgResponse;
                })
                .exceptionally(throwable -> {
                    msgResponse.setMessageStatus("ERROR");
                    msgResponse.setErrorMessage("error");
                    return msgResponse;
                }).join();
    }
    
    公共客户响应流程(){
    CustomResponse msgResponse=新CustomResponse();
    List futures=Arrays.asList(dataHelper.fetchAndUploadCSV1(),
    dataHelper.fetchAndUploadCSV2(),
    dataHelper.fetchAndUploadCSV3(),
    dataHelper.fetchAndUploadCSV4(),
    dataHelper.fetchAndUploadCSV5(),
    dataHelper.fetchAndUploadCSV6(),
    dataHelper.fetchAndUploadCSV7());
    return CompletableFuture.allOf(futures.toArray(新的CompletableFuture[0]))
    。然后应用(v->{
    msgressponse.setProcessed(true);
    msgressponse.setMessageStatus(“消息”);
    返回msgResponse;
    })
    .例外情况下(可丢弃->{
    msgressponse.setMessageStatus(“错误”);
    msgressponse.setErrorMessage(“错误”);
    返回msgResponse;
    }).join();
    }
    

    返回一个新的
    CompletableFuture
    ,当所有给定的CompletableFutures完成时,该新的
    CompletableFuture将完成。因此,当在
    中调用
    join
    ,然后在apply
    中调用时,它会立即返回。本质上,加入是发生在已经完成的期货市场上。这样就消除了阻塞。另外,为了处理可能的异常,应该调用异常的

    您在哪个Java版本上运行此操作?您是否尝试过最新版本的Java 8或Java 10+,正如链接错误中指出的那样?我正在运行Java 8(u201-b09)。最新的Java8是u211。我试试看。还没有试过JDK 10。无论如何,我无法在部署中升级JDK。错误的模糊状态可能表明它是相关的。如果你能可靠地复制它,也许可以提交一份新的记录单。是的,我一直在尝试在没有所有业务逻辑和数据库cal的情况下复制它