Skip to main content

Command Palette

Search for a command to run...

Speed Up API Calls with Java's HttpClient

Updated
•2 min read•View as Markdown

While integrating with an external service, I needed to make high-volume API calls as efficiently as possible. The service responds in under 10ms, and blocking threads would slow everything down.
To solve this, I used Java's built-in HttpClient and its sendAsync() method. Here's why this approach works well:

✅ Java's HttpClient + sendAsync() = Non-Blocking Calls – The same thread can make multiple API calls without waiting for each response.

✅ Process Responses Efficiently – Once the response is ready, use thenAccept() to process the response. This allows any available thread from the thread pool to pick up and handle the response, improving resource utilization.

✅ Handle Failures Properly – Use .exceptionally() or .handle() (if you want to process both success and failure) to manage errors, as sendAsync does not throw exceptions synchronously.

Quick Example:

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class AsyncHttpClientExample {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        HttpClient client = HttpClient.newBuilder().executor(executor).build();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://jsonplaceholder.typicode.com/todos/1"))
                .build();

        client.sendAsync(request, BodyHandlers.ofString())
                .thenAccept(response -> System.out.println("Response: " + response.body()))
                .exceptionally(ex -> {
                    System.err.println("Request failed: " + ex.getMessage());
                    return null;
                });

        Thread.sleep(2000); // Should not be used, refer Best Practices
        executor.shutdown();
    }
}

🔹 Best Practices:

  • Define HttpClient and ExecutorService in a configuration file instead of creating them inside methods.

  • Avoid Thread.sleep() for waiting; instead, use CompletableFuture.join(), CompletableFuture.get(), or CountDownLatch.

  • Consider using .orTimeout() with sendAsync

💡 Optimize Your Thread Pool:

  • I/O-bound tasks (like API calls and DB queries) benefit from larger thread pools since threads spend most of their time waiting.

  • CPU-bound tasks should not exceed the number of CPU cores to prevent unnecessary context switching and performance drops.

#Java #HttpClient #Async #Java11 #SpringBoot #Performance #Coding #API #Scalability