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

How to execute CompletableFuture function and get the result either which of them is done first?

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

我不知道所有方法的签名,但是如果你在某个地方 returning supplyAsync 中的 CompletionStage 而你不使用 thenCompose 相反,该函数将 return 忽略 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 并行查找方法(如果顺序无关紧要),但在这种情况下,您需要确保使用线程列表的实现安全的。 它看起来像这样:

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;