Waiting for callback for multiple futures

2020-06-03 07:45发布

Recently I've delved into a little bit of work using an API. The API uses the Unirest http library to simplify the work of receiving from the web. Naturally, since the data is called from the API server, I tried to be efficient by using asynchronous calls to the API. My idea is structured as follows:

  1. Create array of data by returning the results of futures
  2. Display data + additional information gathered from the data

Therefore, I need to have all the data returned before I can start the second step. My code is as follows:

Future < HttpResponse < JsonNode >  > future1 = Unirest.get("https://example.com/api").asJsonAsync(new Callback < JsonNode > () {
    public void failed(UnirestException e) {
        System.out.println("The request has failed");
    }
    public void completed(HttpResponse < JsonNode > response) {
        System.out.println(response.getBody().toString());
        responses.put(response);
    }
    public void cancelled() {
        System.out.println("The request has been cancelled");
    }
});
Future < HttpResponse < JsonNode >  > future2 = Unirest.get("https://example.com/api").asJsonAsync(new Callback < JsonNode > () {
    public void failed(UnirestException e) {
        System.out.println("The request has failed");
    }
    public void completed(HttpResponse < JsonNode > response) {
        System.out.println(response.getBody().toString());
        responses.put(response);
    }
    public void cancelled() {
        System.out.println("The request has been cancelled");
    }
});
doStuff(responses);

How would I make it so doStuff is called only after both of the futures are finished?

1条回答
孤傲高冷的网名
2楼-- · 2020-06-03 08:32

There are a few options. The code you have now calls doStuff from the same thread where you make your requests. If you want to block until both requests have completed you could use a CountDownLatch. Something like:

CountDownLatch responseWaiter = new CountDownLatch(2);

Future <HttpResponse<JsonNode>> future1 = Unirest.get("https://example.com/api").asJsonAsync(new Callback<JsonNode>() {
  public void completed(HttpResponse<JsonNode> response) {
    responses.put(response);
    responseWaiter.countDown();
  }
  ...
});

// Similar code for the other get call
...

responseWaiter.await();
doStuff(responses);

If you don't want to block that thread until both calls are complete, you could have each of your anonymous inner Callback classes increment an AtomicInteger. When the count is 2 you'd call doStuff. Something like:

AtomicInteger numCompleted = new AtomicInteger();

Future <HttpResponse<JsonNode>> future1 = Unirest.get("https://example.com/api").asJsonAsync(new Callback<JsonNode>() {
  public void completed(HttpResponse<JsonNode> response) {
    responses.put(response);
    int numDone = numCompleted.incrementAndGet();
    if (numDone == 2) {
      doStuff(responses);
    }
  }
});
查看更多
登录 后发表回答