2013-02-14 136 views
36

我正在調用REST URL並嘗試測量獲取響應所花費的時間。BasicClientConnManager的無效使用:仍然分配的連接

我正在使用DefaultHttpClient來獲得REST URL的響應。

在我的下面的程序中,每個線程將在一個特定的範圍內工作。像每個線程將工作之間1 - 100和第二個線程將工作之間101 - 200

SO在我的下面的代碼,它第一次工作正常。但第二次,是在這條線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); 
     } 
    } 
} 

那麼它是好還是不好?

回答

37

我在這裏做什麼錯了?

是的。正如the docs說:

BasicClientConnectionManager是一個簡單的連接管理器, 保持在同一時間只有一個連接。即使這個類是 線程安全的,它應該只被一個執行線程使用。 BasicClientConnectionManager將努力重複使用 連接用於具有相同路由的後續請求。但是,如果持續連接的路由與連接請求的 不匹配,它將關閉現有連接併爲給定的 路由重新打開它。如果連接已經被分配了 ,則拋出java.lang.IllegalStateException。

默認情況下,HttpClient使用BasicClientConnectionManager。

請參閱"Multithreaded request execution"關於如何使用可以跨多個線程處理請求的pooling connection manager

+0

感謝瑞安的建議。我已經更新了代碼。如果我這樣做,那麼我會遇到任何問題? – AKIWEB 2013-02-14 01:39:04

+1

從你展示的片段中很難說。這聽起來像你有一個HttpClient跨越線程,這是基本的連接管理器不允許的。我想這也可能是因爲你沒有在第一個版本中正確[釋放低級資源](http://hc.apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html#d5e139)案件。 – 2013-02-14 01:44:51

+0

糾正我,如果我錯了,但在他的代碼httpClient不共享。在C#中,線程是一種方法,但在Java中它是整個類(jj09.net/multithreading-csharp-vs-java)。所以是的問題是資源發佈(https://www.securecoding.cert.org/confluence/x/9gFqAQ,https://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache /http/util/EntityUtils.html#consume(org.apache.http.HttpEntity))。 – 2016-02-17 12:49:00

37

假設您使用的是香草DefaultHttpClient(內部使用BasicClientConnectionManager),您首先需要使用未完成/最後一個響應。

EntityUtils.consumeQuietly(httpResponse.getEntity());

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

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

+1

首先確保只有一個線程使用DefaultHttpClient;然後對於每次執行,請不要忘記httpResponse.getEntity()。 – Codefor 2013-09-25 01:15:02

+1

第一個建議是強大的。第二個不是,因爲重新分配Http客戶端並不便宜 – asgs 2017-02-08 13:18:56

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

相關問題