5.1 Метод sendAsync()

Также с помощью HttpClient’а можно посылать асинхронные запросы. Обычно это делают в трех случаях.

Первый случай – это запрос будет выполняться очень долго, например, отправка/получение файла. Тогда эту операцию запускают и выполняют асинхронно.

Второй случай – тебе нужно отправлять запросы очень часто, и ты не хочешь ждать ответа от предыдущего запроса перед отправкой следующего.

И наконец, третий случай – тебе не важен результат твоего запроса. Например, ты раз в минуту делаешь скриншот своего экрана и отправляешь его на сервер. То есть логика твоего приложения предполагает, что запросов много и доходят не все. Тогда удобно работать по принципу – отправил и забыл.

Для того, чтобы отправить асинхронный запрос, нужно вызвать метод sendAsync() у объекта класса HttpClient. Этот метод мгновенно завершает работу и возвращает объект CompletableFuture<HttpResponse>. С его помощью можно отследить, когда запрос реально выполнится, а также выполнить определенный код после завершения запроса. Пример:


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

Метод sendAsync() возвращает объект CompletableFuture, который внутри себя содержит HttpResponse, который внутри себя содержит строку, которую вернет сервер.

5.2 Метод executor(), ExecutorService

Также HttpClient позволяет передать в него ExecutorService (пул потоков), которые будут использоваться для выполнения асинхронных запросов. Собственно, в серверных Java-приложениях так всегда и делают.

Ведь если на каждый входящий запрос к твоему API, ты будешь запускать несколько асинхронных запросов еще куда-то, вам никаких потоков не хватит. Пример:


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());

Если пул потоков не задан, то по умолчанию используется java.util.concurrent.Executors.newCachedThreadPool().