Invalid use of BasicClientConnManager: connection

2020-02-17 06:26发布

问题:

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?

回答1:

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.



回答2:

Assuming you are using the vanilla DefaultHttpClient (which uses BasicClientConnectionManager internally), you first need to consume the outstanding/last response.

EntityUtils.consumeQuietly(httpResponse.getEntity());

Else, you can reallocate DefaultHttpClient each time.

Source: Workaround to not shutdown DefaultHttpClient() each time after usage



回答3:

This is my configuration for RestTemplate using pool connection manager. It works very well in 5 more concurrent threads.

<!-- RestTemplate -->
<beans:bean id="restTemplateYT" class="org.springframework.web.client.RestTemplate">
    <beans:constructor-arg ref="httpRequestFactoryYT" />
</beans:bean>

<beans:bean id="httpRequestFactoryYT" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory"> 
    <beans:constructor-arg>
        <beans:bean class="org.apache.http.impl.client.DefaultHttpClient">
            <beans:constructor-arg>
                <beans:bean class="org.apache.http.impl.conn.PoolingClientConnectionManager"/>
            </beans:constructor-arg>
        </beans:bean>
    </beans:constructor-arg>
    <beans:property name="connectTimeout" value="5000" />
</beans:bean>

Spring version: 3.1.0