Java 11 HttpClient - What is Optimum Ratio of HttpClients to Concurrent HttpRequests

6.1k views Asked by At

In the example below I create one Java 11 httpClient and then create multiple concurrent HttpRequests.

  1. Is this bad practice?
  2. Should each HttpRequest have its own HttpClient?
  3. Is there an upper limit on the number of HttpRequests a HttpClient can have?

Code

    private static void httpClientExample(){
    
    HttpClient httpClient = HttpClient.newHttpClient();

    System.out.println("TP1");

    var task1 = httpClient.sendAsync(HttpRequest.newBuilder()
            .uri(URI.create("https://www.bing.com/"))
            .build(), HttpResponse.BodyHandlers.ofString())
            .thenApply(HttpResponse::uri).thenAccept(System.out::println);

    var task2 = httpClient.sendAsync(HttpRequest.newBuilder()
            .uri(URI.create("https://openjdk.java.net/"))
            .build(), HttpResponse.BodyHandlers.ofString())
            .thenApply(HttpResponse::uri).thenAccept(System.out::println);
    
    var task3 = httpClient.sendAsync(HttpRequest.newBuilder()
            .uri(URI.create("https://www.google.co.uk/"))
            .build(), HttpResponse.BodyHandlers.ofString())
            .thenApply(HttpResponse::uri).thenAccept(System.out::println);


    System.out.println("Requests Sent");

    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("Main Thread Completed");
    }
2

There are 2 answers

5
ernest_k On BEST ANSWER

This is not explicitly documented in the API docs of HttpClient. But it would be expected that an HttpClient is designed to handle multiple requests. This is in a sense implied on Introduction to the Java HTTP Client:

Once built, an HttpClient can be used to send multiple requests.

Now, your question is likely about managing concurrency on your clients. Rather than with using the same instance of HttpClient, this has much to do with the executor service it uses, which is something you can customize (see here):

ExecutorService executorService = Executors.newFixedThreadPool(10);
HttpClient httpClient  = HttpClient.newBuilder()
                               .executor(executorService)
                               ... //more config
                               .build();

This way, you can manage the thread pool used by the client to run asynchronous requests.

In other words:

Is this bad practice?

No

Should each HttpRequest have its own HttpClient?

No

Is there an upper limit on the number of HttpRequests a HttpClient can have?

You will have to test the optimal concurrency settings for your application and then use an executor service configured accordingly.

2
dbaltor On

I'd say it's all about the number of threads rather than the number of objects as each client can use many threads via an Executor's thread pool, whether explicitly declared or the default one. So the real question boils down to how many threads should we use? That will depend on the use of synchronous or asynchronous requests.

  1. When using send, the more threads we use from the pool, the more requests we will be able to make in parallel until the point where the OS starts threashing, i.e. increasing the number of active threads actually decreases the amount of the work accomplished.
  2. When using sendAsync as in your example, things get interesting as it is a non-blocking method which means the same thread can make multiple requests whilst waiting for responses to process. In this scenario, I'd advise to keep the number of threads in the Executor's pool equal to the number of processors' cores.