Invalid use of BasicClientConnManager: connection still allocated

AKIWEB picture AKIWEB · Feb 14, 2013 · Viewed 58.3k times · Source

I am making a call to REST URL and trying to measure how much time it is taking to get the response back.

I am using DefaultHttpClient for that to get the response back from REST URL.

In my below program , each thread will be working on a particular range. Like Each Thread will work between 1 - 100 and second thread will work between 101 - 200 etc.

SO in my below code, for the first time it works fine. But for the second time, it is throwing exception on this line httpclient.execute for the second time as-

java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.

Is there anything wrong I am doing here?-

Below is my code-

class Task implements Runnable {

    private DefaultHttpClient httpclient = new DefaultHttpClient();
    private HttpGet httpGet;
    private HttpResponse response;

    @Override
    public void run() {

        try {

            httpGet = new HttpGet(
                    "http://localhost:8080/service/BEService/v1/get/USERID=10000/profile.ACCOUNT.SERVICE
            httpGet.getRequestLine();

            for (int userId = id; userId < id + noOfTasks; userId++) {

                    long start = System.nanoTime();

                    response = httpclient.execute(httpGet);

                    long end = System.nanoTime() - start;
                }
        } catch (Exception e) {
            LOG.error("Threw a Exception in " + getClass().getSimpleName(), e);
        }
    }
}

Updated Code:-

If I am doing it something like this-

class Task implements Runnable {

    private DefaultHttpClient httpclient = new DefaultHttpClient();
    private HttpGet httpGet;
    private HttpResponse response;

    @Override
    public void run() {

        try {

            for (int userId = id; userId < id + noOfTasks; userId++) {

                httpGet = new HttpGet("http://localhost:8080/service/BEService/v1/get/USERID=10000/profile.ACCOUNT.SERVICE");
                httpGet.getRequestLine();

                long start = System.nanoTime();

                response = httpclient.execute(httpGet);

                long end = System.nanoTime() - start;

                HttpEntity entity = response.getEntity();
                EntityUtils.consume(entity);
                }
        } catch (Exception e) {
            LOG.error("Threw a Exception in " + getClass().getSimpleName(), e);
        }
    }
}

then it is fine or not?

Answer

Ryan Stewart picture Ryan Stewart · Feb 14, 2013

Is there anything wrong I am doing here?

Yes. As stated in the docs:

BasicClientConnectionManager is a simple connection manager that maintains only one connection at a time. Even though this class is thread-safe it ought to be used by one execution thread only. BasicClientConnectionManager will make an effort to reuse the connection for subsequent requests with the same route. It will, however, close the existing connection and re-open it for the given route, if the route of the persistent connection does not match that of the connection request. If the connection has been already been allocated, then java.lang.IllegalStateException is thrown.

BasicClientConnectionManager is used by HttpClient per default.

See "Multithreaded request execution" on how to use a pooling connection manager that can handle requests across multiple threads.