5.1 método sendAsync()

Você também pode enviar solicitações assíncronas usando HttpClient. Geralmente isso é feito em três casos.

O primeiro caso é que a requisição vai demorar muito , por exemplo, enviar/receber um arquivo. Esta operação é então iniciada e executada de forma assíncrona.

O segundo caso é que você precisa enviar solicitações com muita frequência e não quer esperar a resposta da solicitação anterior antes de enviar a próxima.

E, finalmente, o terceiro caso - o resultado do seu pedido não é importante para você . Por exemplo, você tira uma captura de tela de sua tela uma vez por minuto e a envia para o servidor. Ou seja, a lógica da sua aplicação assume que existem muitos pedidos e nem todos os atingem. Então é conveniente trabalhar de acordo com o princípio - enviar e esquecer.

Para enviar uma solicitação assíncrona, você precisa chamar um método sendAsync()em um objeto da classe HttpClient. Este método sai imediatamente e retorna um arquivo CompletableFuture<HttpResponse>. Com ele, você pode acompanhar quando a solicitação é realmente executada, bem como executar determinado código após a conclusão da solicitação. Exemplo:

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

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

O método sendAsync()retorna um objeto CompletableFutureque contém um HttpResponse dentro, que contém a string que o servidor retornará.

5.2 O método executor(), ExecutorService

Além disso, o HttpClient permite que você passe para ele ExecutorService(um pool de threads) que será usado para executar solicitações assíncronas. Na verdade, em aplicativos Java do lado do servidor, isso sempre é feito.

Afinal, se para cada solicitação recebida em sua API, você iniciar várias solicitações assíncronas em outro lugar, não terá threads suficientes. Exemplo:

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

Se o pool de encadeamentos não estiver definido, o padrão será .java.util.concurrent.Executors.newCachedThreadPool()