java - 如何知道所有异步 HTTP 调用已完成
问题描述
我试图弄清楚如何确定我发出的所有异步 HTTP GET 请求是否都已完成,以便我可以执行另一种方法。对于上下文,我有类似于以下代码的内容:
public void init() throws IOException {
Map<String, CustomObject> mapOfObjects = new HashMap<String, CustomObject>();
ObjectMapper mapper = new ObjectMapper();
// some code to populate the map
mapOfObjects.forEach((k,v) -> {
HttpClient.asyncGet("https://fakeurl1.com/item/" + k, createCustomCallbackOne(k, mapper));
// HttpClient is just a wrapper class for your standard OkHTTP3 calls,
// e.g. client.newcall(request).enqueue(callback);
HttpClient.asyncGet("https://fakeurl2.com/item/" + k, createCustomCallbackTwo(k, mapper));
});
}
private createCustomCallbackOne(String id, ObjectMapper mapper) {
return new Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
try (ResponseBody body = response.body()) {
CustomObject co = mapOfObjects.get(id);
if (co != null) {
co.setFieldOne(mapper.readValue(body.byteStream(), FieldOne.class)));
}
} // implicitly closes the response body
}
}
@Override
public void onFailure(Call call, IOException e) {
// log error
}
}
}
// createCustomCallbackTwo does more or less the same thing,
// just sets a different field and then performs another
// async GET in order to set an additional field
那么监视所有这些异步调用以确保它们已完成并且我可以对存储在地图中的对象执行另一种方法的最佳/正确方法是什么?
解决方案
最简单的方法是计算有多少请求“正在运行”。为每个入队的请求增加它,在回调结束时减少它。当/如果计数为 0,则任何/所有请求都已完成。使用信号量或计数锁,您可以wait
使其变为 0 而无需轮询。
请注意,回调在不同的线程上运行,因此您必须提供某种同步。
如果你想为每个请求创建一个新的回调,你可以使用这样的东西:
public class WaitableCallback implements Callback {
private boolean done;
private IOException exception;
private final Object[] signal = new Object[0];
@Override
public void onResponse(Call call, Response response) throws IOException {
...
synchronized (this.signal) {
done = true;
signal.notifyAll();
}
}
@Override
public void onFailure(Call call, IOException e) {
synchronized (signal) {
done = true;
exception = e;
signal.notifyAll();
}
}
public void waitUntilDone() throws InterruptedException {
synchronized (this.signal) {
while (!this.done) {
this.signal.wait();
}
}
}
public boolean isDone() {
synchronized (this.signal) {
return this.done;
}
}
public IOException getException() {
synchronized (this.signal) {
return exception;
}
}
}
为每个请求创建一个实例并将其放入例如List<WaitableCallback> pendingRequests
.
然后你可以等待所有请求完成:
for ( WaitableCallback cb : pendingRequests ) {
cb.waitUntilDone();
}
// At this point, all requests have been processed.
但是,您可能不应该为每个请求创建一个新的相同回调对象。回调的方法获取Call
作为参数传递的参数,以便代码可以检查它以确定它正在处理哪个请求;在您的情况下,您似乎甚至不需要它。因此,对于应该以相同方式处理的请求,请使用单个 Callback 实例。
推荐阅读
- python - 我可以像在 Java 中那样在 Python 中声明一个固定类型为整数的变量吗?
- python - 使用 CSV 数据作为 TensorFlow 推荐器的输入
- python - 获取数据框中每个数据的最小值
- c++ - 下级停止了,因为它收到了来自操作系统的信号。信号名称:SIGSEGV 信号含义:分段错误
- testing - 寻找一种能够记录选择器功能链的“合法”方式
- go - 类型定义是否有助于分配受限值?
- vue.js - 我无法运行带有 Nuxt 致命错误的 vue 项目
- mysql - 需要使用 SQL 从数据集中计算一些指标 - 单独的查询
- flutter - google_mobile_ads 0.13.0 插件横幅广告在颤振应用中调用 setstate 时自动重新加载
- python - 我在 pycharm 上下载 Flask-MySQLdb 时遇到问题,并且一直收到此错误