【问题标题】:How to execute CompletableFuture function and get the result either which of them is done first?如何执行 CompletableFuture 函数并获得其中哪一个先完成的结果?
【发布时间】:2021-04-27 07:20:46
【问题描述】:

我已经创建了 3 个对数据库执行查询的函数,然后我想获取每个结果并添加到一个对象列表中,但结果始终为空,我该如何正确执行此操作?这就是我要做的:

我创建了 3 个 CompletableFuture 函数:

private CompletableFuture<List<TransSalesOrderOnlyResponseDto>> findPureUnAssignedSO() {
    return CompletableFuture.supplyAsync(() -> iSalesOrderMapper.entityToSOOnlyDto(iTransSalesOrderQdslRepository.findUnAssignedSalesOrder()));
}

private CompletableFuture<List<TransSalesOrderOnlyResponseDto>> findSOHaveItemLeftOverOnly() {
    return CompletableFuture.supplyAsync(() -> {
        List<TransSalesOrder> transSalesOrders = iTransSalesOrderQdslRepository.findSOHaveLeftOverButDone();
        return buildTransSalesOrdersResponseNew(transSalesOrders);
    });
}

private CompletableFuture<List<TransSalesOrderOnlyResponseDto>> findSalesOrderWithBpsjInDeliveryOrder() {
    return CompletableFuture.supplyAsync(() -> {
        List<TransSalesOrder> transSalesOrders = iTransSalesOrderQdslRepository.findSalesOrderWithBpsjInDeliveryOrder();

        return buildTransSalesOrdersBpsjOnlyResponseNew(transSalesOrders); 
    });
}

然后这是我尝试执行这 3 个功能的方法:

尝试 1,使用 get() :

public List<TransSalesOrderOnlyResponseDto> findUnAssignedSO() {
    CompletableFuture<List<TransSalesOrderOnlyResponseDto>> future = new CompletableFuture<>();

    List<TransSalesOrderOnlyResponseDto> transSalesOrdersResponseNew = new ArrayList<>();
    try {
        transSalesOrdersResponseNew = findSOHaveItemLeftOverOnly().get();
        transSalesOrdersResponseNew.addAll(findPureUnAssignedSO().get());
        transSalesOrdersResponseNew.addAll(findSalesOrderWithBpsjInDeliveryOrder().get());
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }

    return transSalesOrdersResponseNew;
}

结果还是空

尝试 2:

public List<TransSalesOrderOnlyResponseDto> findUnAssignedSO() {
    List<TransSalesOrderOnlyResponseDto> transSalesOrdersResponseNew = new ArrayList<>();

    CompletableFuture<List<TransSalesOrderOnlyResponseDto>> soHaveItemLeftOverOnly = findSOHaveItemLeftOverOnly();
    CompletableFuture<List<TransSalesOrderOnlyResponseDto>> pureUnAssignedSO = findPureUnAssignedSO();
    CompletableFuture<List<TransSalesOrderOnlyResponseDto>> salesOrderWithBpsjInDeliveryOrder = findSalesOrderWithBpsjInDeliveryOrder();

    CompletableFuture.allOf(soHaveItemLeftOverOnly, pureUnAssignedSO, salesOrderWithBpsjInDeliveryOrder)
            .thenRun(() -> {
                transSalesOrdersResponseNew.addAll(soHaveItemLeftOverOnly.join());
                transSalesOrdersResponseNew.addAll(pureUnAssignedSO.join());
                transSalesOrdersResponseNew.addAll(salesOrderWithBpsjInDeliveryOrder.join());
                });

    }

    return transSalesOrdersResponseNew;
}

如果我这样做,结果总是空的,即使我使用 .get() 来阻止结果,我该如何正确地完成 completablefuture?

【问题讨论】:

    标签: java spring-boot asynchronous completable-future


    【解决方案1】:

    您的两次尝试都不起作用,因为您在没有等待结果的情况下调用了完成阶段(虽然我不确定第 1 次尝试)。

    我不知道所有方法的签名,但是如果您在 supplyAsync 中的某个地方返回 CompletionStage 而您不使用 thenCompose,则该函数将返回忽略结果完成阶段

    在第 2 次尝试中,更容易看出哪里出错了。就是这个部分:

    CompletableFuture.allOf(...).thenRun(() -> ...);
    

    您在thenRun 部分中的操作无关紧要。您无需在任何地方等待结果,因此它会立即到达return transSalesOrdersResponseNew;,即使您在thenRun 部分中定义的函数尚未完成。

    假设findSOHaveItemLeftOverOnlyfindPureUnAssignedSOfindSalesOrderWithBpsjInDeliveryOrder方法是正确的(从你给出的使用细节我们无法知道),你可以这样重写代码:

    final List<TransSalesOrderOnlyResponseDto> transSalesOrdersResponseNew = ... ;
    
    findSOHaveItemLeftOverOnly()
       .thenAccept( transSalesOrdersResponseNew::addAll )
       .thenCompose( v -> findPureUnAssignedSO() )
       .thenAccept( transSalesOrdersResponseNew::addAll )
       .thenCompose( v -> findSalesOrderWithBpsjInDeliveryOrder() )
       .thenAccept( transSalesOrdersResponseNew::addAll )
       .join();
    
    return transSalesOrdersResponseNew;
    

    请注意,我使用的是.thenCompose,这将使用函数的结果作为序列中的下一个CompletionStage。这样您就不会在过程中丢失结果。

    您还可以使用CompletableFuture.allOf 并行运行 find 方法(如果顺序无关紧要),但在这种情况下,您需要确保使用线程安全的 List 实现。 它看起来像这样:

    final List<TransSalesOrderOnlyResponseDto> transSalesOrdersResponseNew = ... // Thread-safe list implementation;
    
    CompletableFuture.allOf(
        findSOHaveItemLeftOverOnly().thenAccept( transSalesOrdersResponseNew::addAll ),
        findPureUnAssignedSO().thenAccept( transSalesOrdersResponseNew::addAll ),
        findSalesOrderWithBpsjInDeliveryOrder().thenAccept( transSalesOrdersResponseNew::addAll )
    ).join();
    
    return transSalesOrdersResponseNew;
    

    【讨论】:

    • 我刚刚意识到你可以使用方法参考
    • 哦认为这种方式应该可行,因为我刚刚收到错误 org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.bit.microservices.b2b.warehouse.entity.TransSalesOrder.transDeliveryOrder ,无法初始化代理 - 没有会话,我应该先谷歌它
    • 不过,该错误与问题无关。无论如何,我在回答中添加了一些细节,试图解释为什么您使用的其他方法不起作用。
    • 如果您提出的问题正确,请记住接受答案
    • 当然,解释得很好,它可以工作,谢谢你 Davide
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多