如何执行 CompletableFuture 函数并获得结果,其中哪一个先完成?

问题描述

我已经创建了 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

解决方法

您的两次尝试均无效,因为您在未等待结果的情况下调用了完成阶段(尽管我不确定第 1 次尝试)。

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

在尝试 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;