在重用apache httpclient时阻塞线程

我使用apache httpclient 4.3.4,我想在工作线程中重用httpclient实例,但是当httpclient第二次发布数据时线程被阻塞了。

class SinglePostConnectionThread extends Thread { void processResponse(CloseableHttpResponse response) throws Exception{ try{ StatusLine sLine = response.getStatusLine(); switch (sLine.getStatusCode()){ case 200:{ break; } case 204:{ //HttpEntity entity = response.getEntity(); //entity.getContent().close(); System.out.println("No Flight"); break; } default: System.out.println("Bad response"); } } catch (Exception e){ System.out.println(e.getMessage()); }finally { System.out.println("Close response"); response.close(); } } @Override public void run() { BasicHttpClientConnectionManager basicConnManager = new BasicHttpClientConnectionManager(); HttpClientContext context = HttpClientContext.create(); try { CloseableHttpClient client = HttpClients.custom().setConnectionManager(basicConnManager).build(); int tmpLoop = loopNum; while (tmpLoop > 0) { HttpPost post = new HttpPost(host); StringEntity se = new StringEntity(toJson(bid), "utf-8"); post.setHeader(HTTP.CONTENT_TYPE, "application/json"); post.setEntity(se); processResponse(client.execute(post, context));//blocked when running at second time tmpLoop--; if (loopNum ==0){ tmpLoop = 1; } post.releaseConnection(); //basicConnManager.; } } catch (Exception e){ e.printStackTrace(); } } } 

似乎连接已用完,但我实际上关闭了所有资源。

您不能在multithreading环境中使用Simple Connection Manager ,即使此类是线程安全的,它也应该仅由一个执行线程使用。

摘自Apache HTTP Components教程

2.3.2。 简单连接管理器

BasicHttpClientConnectionManager是一个简单的连接管理器,一次只能维护一个连接。 即使这个类是线程安全的,它也应该只由一个执行线程使用。 BasicHttpClientConnectionManager将努力为具有相同路由的后续请求重用连接。 但是,如果持久连接的路由与连接请求的路由不匹配,它将关闭现有连接并为给定路由重新打开它。 如果已经分配了连接,则抛出java.lang.IllegalStateException。

所以,您使用了Pooling连接管理器

2.3.3。 池连接管理器

PoolingHttpClientConnectionManager是一个更复杂的实现,它管理客户端连接池,并且能够为来自多个执行线程的连接请求提供服务。 连接以每个路由为基础进行池化。 管理员已经在池中提供持久连接的路由请求将通过从池租用连接而不是创建全新连接来进行服务。

PoolingHttpClientConnectionManager维护每个路由和总计的最大连接数限制。 默认情况下,此实现将为每个给定路由创建不超过2个并发连接,并且总共不再有20个连接。 对于许多实际应用程序而言,这些限制可能过于严格,尤其是当它们使用HTTP作为其服务的传输协议时。

您可以查看Threaded请求执行示例

 package org.apache.http.examples.client; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; /** * An example that performs GETs from multiple threads. * */ public class ClientMultiThreadedExecution { public static void main(String[] args) throws Exception { // Create an HttpClient with the ThreadSafeClientConnManager. // This connection manager must be used if more than one thread will // be using the HttpClient. PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); cm.setMaxTotal(100); CloseableHttpClient httpclient = HttpClients.custom() .setConnectionManager(cm) .build(); try { // create an array of URIs to perform GETs on String[] urisToGet = { "http://hc.apache.org/", "http://hc.apache.org/httpcomponents-core-ga/", "http://hc.apache.org/httpcomponents-client-ga/", }; // create a thread for each URI GetThread[] threads = new GetThread[urisToGet.length]; for (int i = 0; i < threads.length; i++) { HttpGet httpget = new HttpGet(urisToGet[i]); threads[i] = new GetThread(httpclient, httpget, i + 1); } // start the threads for (int j = 0; j < threads.length; j++) { threads[j].start(); } // join the threads for (int j = 0; j < threads.length; j++) { threads[j].join(); } } finally { httpclient.close(); } } /** * A thread that performs a GET. */ static class GetThread extends Thread { private final CloseableHttpClient httpClient; private final HttpContext context; private final HttpGet httpget; private final int id; public GetThread(CloseableHttpClient httpClient, HttpGet httpget, int id) { this.httpClient = httpClient; this.context = new BasicHttpContext(); this.httpget = httpget; this.id = id; } /** * Executes the GetMethod and prints some status information. */ @Override public void run() { try { System.out.println(id + " - about to get something from " + httpget.getURI()); CloseableHttpResponse response = httpClient.execute(httpget, context); try { System.out.println(id + " - get executed"); // get the response body as an array of bytes HttpEntity entity = response.getEntity(); if (entity != null) { byte[] bytes = EntityUtils.toByteArray(entity); System.out.println(id + " - " + bytes.length + " bytes read"); } } finally { response.close(); } } catch (Exception e) { System.out.println(id + " - error: " + e); } } } }