![](/img/trans.png)
[英]How to run multiple service calls in parallel using CompletableFuture?
[英]How to call a method multiple times in parallel using CompletableFuture in Spring Boot
我在Spring Boot中有一个Web服务,它需要向外部Web服务发出请求以检索多个货币对的实时汇率。
当前进行外部API调用的方法如下所示;
@Async
public CompletableFuture<Double> getBaseRateForCurrencyPair(String sourceCurrency, String targetCurrency) {
String key = sourceCurrency.toUpperCase() + targetCurrency.toUpperCase();
Double baseRate = 0.00;
String baseRateProviderUrl = "https://apilayer.net/api/live?access_key=" + currencyLayerAccessKey + "&source=" + sourceCurrency + "¤cies=" + targetCurrency;
HttpClientRequest clientRequest = new HttpClientRequest(baseRateProviderUrl);
try {
Response response = clientRequest.get();
String responseStr = response.body().string();
JSONObject jsonObject = new JSONObject(responseStr);
baseRate = AppHelper.round(jsonObject.getJSONObject("quotes").getDouble(key), 2);
} catch (Exception e) {
e.printStackTrace();
}
return CompletableFuture.completedFuture(baseRate);
}
我想做的就是将此方法称为未知次数,具体取决于我们需要获取多少货币对,等待所有货币对完成并存储要在API响应中返回的结果。
我有一个接收源货币代码和目标货币汇率列表的方法。
public RateResponse getLiveRates(String sourceCurrency, String[] targetCurrencies) {
RateResponse rateResponse = new RateResponse();
rateResponse.setSourceCurrency(sourceCurrency);
/* Loop through target currencies and start a thread for each */
Map<String, CompletableFuture<Double>> ratesMap = new HashMap<>();
for (String targetCurrency : targetCurrencies) {
ratesMap.put(targetCurrency, matrixHelper.getBaseRateForCurrencyPair(sourceCurrency, targetCurrency));
}
/* At this point, I would loop through the Map and grab the results, but only when all are finished */
return rateResponse;
}
我的问题是,我无法弄清楚如何等待所有异步调用完成之后才开始遍历Map并检索结果。
您是否尝试过CompletableFuture
方法allOf(CompletableFuture<?>... cfs)
? 在这里寻找文件
一个简单的解决方案可能如下所示:
Future
对象存储在某些全局集合/列表中 因此,您的第一个代码段更改为:
CompletableFuture rv = CompletableFuture.completedFuture(baseRate);
thatGlobalList.append(rv);
return rv;
接着:
availableFutures = 0;
while (availableFutures < thatGlobalList.size()) {
availableFutures=0;
for (CompletableFuture future : thatGlobalList) {
if (future.isDone()) {
availableFutures++;
}
当然,当您的地图已经为您构建,并且包含所有将来的对象时,只需简单地遍历地图的值即可,并且可以肯定,所有这些都为您提供了isDone()
!
嗯,也许我在这里错过了一些东西,但是如果您迭代所有可完成对象并调用其CompletableFuture#get,那么根据定义,您将在所有期货完成后完成迭代。
即使您使用的是CompletableFuture
,您的getBaseRateForCurrencyPair
方法也仅在完成所有处理后返回。 要并行执行所有这些操作,您将必须使用以下代码:
public CompletableFuture<Double> getBaseRateForCurrencyPair(String sourceCurrency, String targetCurrency) {
CompletableFuture<String> completableFuture
= new CompletableFuture<>();
Executors.newCachedThreadPool().submit(() -> {
String key = sourceCurrency.toUpperCase() + targetCurrency.toUpperCase();
Double baseRate = 0.00;
String baseRateProviderUrl = "https://apilayer.net/api/live?access_key=" + currencyLayerAccessKey + "&source=" + sourceCurrency + "¤cies=" + targetCurrency;
HttpClientRequest clientRequest = new HttpClientRequest(baseRateProviderUrl);
try {
Response response = clientRequest.get();
String responseStr = response.body().string();
JSONObject jsonObject = new JSONObject(responseStr);
baseRate = AppHelper.round(jsonObject.getJSONObject("quotes").getDouble(key), 2);
} catch (Exception e) {
e.printStackTrace();
}
completableFuture.complete(baseRate);
return null;
});
return completableFuture;
}
为了等待所有任务完成,您可以使用如下代码:
CompletableFuture.allOf(ratesMap.values().stream().toArray(CompletableFuture[]::new))
您可以仅迭代地图并使用mapValue.get()
获得Double
值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.