我试图弄清楚如何确定我发出的所有异步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 :(得分:2)
最简单的方法是保持“运行中”请求的数量。对于排队的每个请求,将其递增,在回调结束时将其递减。当/如果计数为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实例。
答案 1 :(得分:1)
如果函数asyncGet调用您的函数createCustomCallbackOne,那么它很简单。
对于每个键,您将调用两个页面。 “ https://fakeurl1.com/item/”和“ https://fakeurl2.com/item/”(忽略+ k)
因此,您需要一张地图来进行处理,仅一个回调函数就足够了。
使用带有按键的地图来指示每个呼叫:
static final Map<String, Integer> trackerOfAsyncCalls = new HashMap<>();
public void init() throws IOException {
Map<String, CustomObject> mapOfObjects = new HashMap<String, CustomObject>();
//need to keep a track of the keys in some object
ObjectMapper mapper = new ObjectMapper();
trackerOfAsyncCalls.clear();
// some code to populate the map
mapOfObjects.forEach((k,v) -> {
HttpClient.asyncGet("https://fakeurl1.com/item/" + k, createCustomCallback(k,1 , 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, createCustomCallback(k, 2, mapper));
trackerOfAsyncCalls.put(k + "-2", null);
});
}
//最后重要 私人createCustomCallbackOne(最终字符串idOuter,int,ObjectMapper映射器){ 返回新的Callback(){ 最终字符串myId = idOuter +“-” +其中;
trackerOfAsyncCalls.put(myId, null);
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
trackerOfAsyncCalls.put(myId, 1);
///or put outside of if if u dont care if success or fail or partial...
现在设置一个线程,或者最好设置一个每5秒发出一次响声的调度程序,检查mapOfObjects和trackerOfAsyncCalls中的所有ey,以查看是否所有键都已启动,并且所有键都已获得最终成功或超时或错误状态。 / p>