Java CompletableFuture allOf approach



我正在尝试使用CompletableFuture方法并行运行3个操作。现在这3个操作返回不同的类型,因此需要分别检索数据。下面是我要做的:

CompletableFuture<List<A>> aFuture = CompletableFuture.supplyAsync (() -> getAList());
CompletableFuture<Map<String,B> bFuture = CompletableFuture.supplyAsync (() -> getBMap());
CompletableFuture<Map<String,C> cFuture = CompletableFuture.supplyAsync (() -> getCMap());
CompletableFuture<Void> combinedFuture =
CompletableFuture.allOf (aFuture, bFuture, cFuture);
combinedFuture.get(); (or join())
List<A> aData = aFuture.get(); (or join)
Map<String, C> bData = bFuture.get(); (or join)
Map<String, C> cData = cFuture.get(); (or join)

这做的工作和工作,但我试图理解,如果我们需要做这些得到/连接结合未来以及个人的,如果有一个更好的方法来做到这一点。

我也试过使用whenComplete()方法,但我想要分配返回数据的变量在方法内,所以我得到了一个最终的局部变量不能被分配,因为它是在java中的封闭类型中定义的;错误,我不想把它们移到类级别

寻找一些专家/替代意见。提前谢谢你

SG

调用getjoin仅表示"等待完成"。它对补全本身没有影响。

调用CompletableFuture.supplyAsync(() -> getAList())时,该方法将立即将供应商的评价提交给公共池。调用者对getAList()执行的唯一影响是,如果没有运行的非守护进程线程,JVM将终止。这在简单的测试程序中是一个常见的错误,它包含了一个不等待完成的main方法。否则,执行getAList()将完成,无论是否查询其结果。

所以当你使用

CompletableFuture<List<A>> aFuture = CompletableFuture.supplyAsync(() -> getAList());
CompletableFuture<Map<String,B>> bFuture=CompletableFuture.supplyAsync(() -> getBMap());
CompletableFuture<Map<String,C>> cFuture=CompletableFuture.supplyAsync(() -> getCMap());
List<A> aData = aFuture.join();
Map<String, B> bData = bFuture.join();
Map<String, C> cData = cFuture.join();

随后的三个supplyAsync调用确保这三个操作可以并发运行。三个join()调用只等待结果,当第三个join()返回时,您就知道所有三个操作都完成了。有可能第一个join()aFuture完成的时候返回,但是其他操作中的一个或两个仍在运行,但是对于三个独立的操作来说,这无关紧要。

当您在单独的join()调用之前执行CompletableFuture.allOf(aFuture, bFuture, cFuture).join();时,它确保所有三个操作在第一个单独的join()调用之前完成,但是正如所说,当所有三个操作都是独立的并且您不依赖于它们的执行的一些副作用时,它没有影响(通常您不应该)。

allOf的实际目的是在而不是想要立即等待结果时构建一个新的未来。例如

record Result(List<A> aData, Map<String, B> bData, Map<String, C> cData) {}
CompletableFuture<Result> r = CompletableFuture.allOf(aFuture, bFuture, cFuture)
.thenApply(v -> new Result(aFuture.join(), bFuture.join(), cFuture.join()));
// return r or pass it to some other code...

在这里,使用allOf更可取,例如

CompletableFuture<Result> r = CompletableFuture.supplyAsync(
() -> new Result(aFuture.join(), bFuture.join(), cFuture.join()));

,因为后者可能会在从供应商调用join()时阻塞工作线程。底层框架可能会在检测到这种情况时进行补偿,例如启动一个新线程,但这仍然是一个昂贵的操作。相比之下,链接到allOf的函数只在所有期货完成后才被评估,因此所有嵌入的join()调用都保证立即返回。

对于少数期货,仍然有allOf的替代方案,例如

var r = aFuture.thenCompose(a ->
bFuture.thenCombine(cFuture, (b, c) -> new Result(a, b, c)));

最新更新