Reusing JAX RS Client in multi-threaded environment (with resteasy) Reusing JAX RS Client in multi-threaded environment (with resteasy) multithreading multithreading

Reusing JAX RS Client in multi-threaded environment (with resteasy)


Your implementation is not thread-safe. When two threads access someMethod at the same time they are sharing the same Client and one will try to make a second request while the first one is not finished.

You have two choices:

  • Synchronize the access to the Client and WebTarget manually.
  • Let the container manage concurrency by annotating the enclosing type with @javax.ejb.Singleton which guarantees thread safety. (see chapter 4.8.5 of the EJB specification)

If someMethod in a container managed environment I would use the second approach.


Since this issue is still open at the time of writing (version 3.0.X) RESTEASY: deprecated Apache classes cleanup

You can go deeper to use the newer, non-deprecated classes instead to create you resteasy client. You will also have more control over how you want the pool to be etc.

Here is what I did:

// This will create a threadsafe JAX-RS client using pooled connections.// Per default this implementation will create no more than than 2// concurrent connections per given route and no more 20 connections in// total. (see javadoc of PoolingHttpClientConnectionManager)PoolingHttpClientConnectionManager cm =        new PoolingHttpClientConnectionManager();CloseableHttpClient closeableHttpClient =        HttpClientBuilder.create().setConnectionManager(cm).build();ApacheHttpClient4Engine engine =        new ApacheHttpClient4Engine(closeableHttpClient);return new ResteasyClientBuilder().httpEngine(engine).build();

Also make sure you release the connection after making a call. Calling response.close() will do that for you so probably put that in a finally block.


First, do not reuse WebTarget. For simplicity, you can always create new WebTarget.

Second, if you're using Resteasy, you can add provided dependency for Resteasy client to your project. Example in Gradle:

    provided 'org.jboss.resteasy:resteasy-client:3.0.14.Final'

Then, you can create your connection like this:

        ResteasyClientBuilder builder = new ResteasyClientBuilder();        builder.connectionPoolSize(200);

There is no need to set maxPooledPerRoute, this is set automatically by RestEasy (can be found in RestEasyClientBuilder class source code).

When you set connectionPoolSize, you will no longer get error when Client is reused and you can happily re-use them all across the application. I've tried this solution on many projects and it actually works well. But when you deploy your application to a non-resteasy container (like Glassfish), your code won't work and you will have to use ClientBuilder class again.