5.1 sendAsync() method

You can also send asynchronous requests using HttpClient. Usually this is done in three cases.

The first case is that the request will take a very long time , for example, sending / receiving a file. This operation is then started and executed asynchronously.

The second case is that you need to send requests very often and you don't want to wait for a response from the previous request before sending the next one.

And finally, the third case - the result of your request is not important to you . For example, you take a screenshot of your screen once a minute and send it to the server. That is, the logic of your application assumes that there are many requests and not all reach them. Then it is convenient to work according to the principle - send and forget.

In order to send an asynchronous request, you need to call a method sendAsync()on an object of the HttpClient class. This method exits immediately and returns a CompletableFuture<HttpResponse>. With it, you can track when the request is actually executed, as well as execute certain code after the request is completed. Example:

HttpClient client = HttpClient.newBuilder().build();

CompletableFuture<HttpResponse<String>> response = client.sendAsync(
        request,
        HttpResponse.BodyHandlers.ofString()
);

The method sendAsync()returns an object CompletableFuturethat contains an HttpResponse inside, which contains the string that the server will return.

5.2 The executor() method, ExecutorService

Also, HttpClient allows you to pass to it ExecutorService(a pool of threads) that will be used to perform asynchronous requests. Actually, in server-side Java applications, this is always done.

After all, if for each incoming request to your API, you will launch several asynchronous requests somewhere else, you will not have enough threads. Example:

ExecutorService executorService = Executors.newFixedThreadPool(2);

CompletableFuture<HttpResponse<String>> response1 = HttpClient.newBuilder()
  .executor(executorService)
  .build()
  .sendAsync(request, HttpResponse.BodyHandlers.ofString());

CompletableFuture<HttpResponse<String>> response2 = HttpClient.newBuilder()
  .executor(executorService)
  .build()
  .sendAsync(request, HttpResponse.BodyHandlers.ofString());

If the thread pool is not set, then the default is .java.util.concurrent.Executors.newCachedThreadPool()