for循环等待所有CompletableFutures给出结果,并将结果添加到int

For loop wait for all CompletableFutures to give result, and add result to int

我有一个方法 getCount(id) returns 来自数据库的整数,作为 CompletableFuture。我想遍历所有的 id,得到所有的结果,并将它们添加到一个全局 int 中。然后我想用那个 int 做点什么:

int totalCount;
for (String id : API.getIDs()) {
    //OtherAPI.getCount(id) will return the CompletableFuture<Integer>
    OtherAPI.getCount(id).thenAccept(count -> totalCount += count);
}

System.out.println("" + totalCount);

这会出错,因为您不能在 thenAccept 中将一个整数与另一个整数相加,因为它是一个消费者。有什么方法可以做到这一点?

注意传递给thenAccept的函数可以由任意线程执行,所以谢天谢地,Java不允许他们修改局部多变的。当您将变量更改为堆上的字段时,编译器会接受它,但结果会完全损坏。

最简单的解决方案是

int totalCount = 0;
for(String id: API.getIDs()) {
    totalCount += OtherAPI.getCount(id).join();
}

它只是等待每个值的可用性,在本地对它们求和。根据 OtherAPI.getCount(…) 调用封装的操作,这甚至可能是最有效的解决方案。

但是当这些操作需要很长时间并且可以真正 运行 并行时,即不依赖于内部共享资源,在所有操作开始之前不等待可能是有益的。

你可以这样做

CompletableFuture<Integer> result = CompletableFuture.completedFuture(0);
for(String id: API.getIDs()) {
    result = result.thenCombine(OtherAPI.getCount(id), Integer::sum);
}
System.out.println(result.join());

这里,整个循环都是wait-free。它将安排求和操作,在完成两个操作后完成。然后,只有最后的join调用才会等待最后的结果。至此,所有的异步操作都已经提交。