I am trying to reuse a Jersey2(Jersey 2.16) Client for async invocation. However after 2 requests, I see that the threads going into a waiting state, waiting on a lock. Since client creation is an expensive operation, I am trying to reuse the client in the async calls. The issue occurs only with ApacheConnectorProvider
as the connector class. I want to use ApacheConnectorProvider
, as I need to use a proxy and set SSL properties and I want to use PoolingHttpClientConnectionManager
.
The sample code is given below:
public class Example {
Integer eventId = 0;
private ClientConfig getClientConfig()
{
ClientConfig clientConfig = new ClientConfig();
ApacheConnectorProvider provider = new ApacheConnectorProvider();
clientConfig.property(ClientProperties.REQUEST_ENTITY_PROCESSING,RequestEntityProcessing.BUFFERED);
clientConfig.connectorProvider(provider);
return clientConfig;
}
private Client createClient()
{
Client client = ClientBuilder.newClient(getClientConfig());
return client;
}
public void testAsyncCall()
{
Client client = createClient();
System.out.println("Testing a new Async call on thread " + Thread.currentThread().getId());
JSONObject jsonObject = new JSONObject();
jsonObject.put("value", eventId++);
invoker(client, "http://requestb.in/nn0sffnn" , jsonObject);
invoker(client, "http://requestb.in/nn0sffnn" , jsonObject);
invoker(client, "http://requestb.in/nn0sffnn" , jsonObject);
client.close();
}
private void invoker(Client client, String URI, JSONObject jsonObject)
{
final Future<Response> responseFuture = client.target(URI)
.request()
.async()
.post(Entity.entity(jsonObject.toJSONString(), MediaType.TEXT_PLAIN));
try {
Response r = responseFuture.get();
System.out.println("Response is on URI " + URI + " : " + r.getStatus());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String args[])
{
Example client1 = new Example();
client1.testAsyncCall();
return;
}
}
The response I see is:
Testing a new Async call on thread 1
Response is on URI http://requestb.in/nn0sffnn : 200
Response is on URI http://requestb.in/nn0sffnn : 200
On looking at the thread stack, I see the following trace:
"jersey-client-async-executor-0" prio=6 tid=0x043a4c00 nid=0x56f0 waiting on condition [0x03e5f000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x238ee148> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043) at org.apache.http.pool.PoolEntryFuture.await(PoolEntryFuture.java:133) at org.apache.http.pool.AbstractConnPool.getPoolEntryBlocking(AbstractConnPool.java:282) at org.apache.http.pool.AbstractConnPool.access$000(AbstractConnPool.java:64) at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:177) at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:170)
Can someone give me a suggestion as to how to reuse Client objects for async requests and may be how to get over this issue as well.