BasicClientConnManager的使用无效:仍然分配了连接

时间:2013-02-14 01:26:53

标签: java rest apache-httpclient-4.x

我正在调用REST URL并尝试测量恢复响应所花费的时间。

我正在使用DefaultHttpClient来获取REST URL的回复。

在我的下面的程序中,每个线程都将在特定范围内工作。就像每个线程在1 - 100之间工作一样,第二个线程可以在101 - 200等之间工作。

在我的下面的代码中,这是第一次正常工作。但这是第二次,它在httpclient.execute这一行作为 -

第二次抛出异常
java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.

我在这里做错了什么? -

以下是我的代码 -

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);
        }
    }
}

更新代码: -

如果我这样做的话 -

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);
        }
    }
}

那么它还不错?

3 个答案:

答案 0 :(得分:44)

  

我在这里做错了吗?

是。如the docs中所述:

  

BasicClientConnectionManager是一个简单的连接管理器   一次只维护一个连接。即使这个班级是   线程安全它应该只由一个执行线程使用。   BasicClientConnectionManager将努力重用   使用相同路由的后续请求的连接。它会,   但是,关闭现有连接并为给定连接重新打开它   route,如果持久连接的路由不匹配   连接请求。如果连接已经存在   allocate,然后抛出java.lang.IllegalStateException。

     

默认情况下,HttpClient使用BasicClientConnectionManager。

请参阅"Multithreaded request execution",了解如何使用可以跨多个线程处理请求的pooling connection manager

答案 1 :(得分:40)

假设您正在使用vanilla DefaultHttpClient(在内部使用BasicClientConnectionManager),您首先需要使用未完成/最后一个响应。

EntityUtils.consumeQuietly(httpResponse.getEntity());

否则,您每次都可以重新分配DefaultHttpClient

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

答案 2 :(得分:1)

这是我使用池连接管理器为RestTemplate配置的。它在另外5个并发线程中运行良好。

<!-- 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版本:3.1.0