我使用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();
}
}
}
似乎连接已用完,但我实际上关闭了所有资源。
答案 0 :(得分:5)
您不能在多线程环境中使用简单连接管理器,即使此类是线程安全的,也只能由一个执行线程使用。
从Apache HTTP Components tutorial
中提取<强> 2.3.2。简单连接管理器
BasicHttpClientConnectionManager是一个简单的连接管理器 一次只维护一个连接。即使这个班级是 线程安全它应该只由一个执行线程使用。 BasicHttpClientConnectionManager将努力重用 使用相同路由的后续请求的连接。它会, 但是,关闭现有连接并为给定连接重新打开它 route,如果持久连接的路由不匹配 连接请求。如果连接已经存在 allocate,然后抛出java.lang.IllegalStateException。
所以,您使用了池连接管理器
<强> 2.3.3。池化连接管理器
PoolingHttpClientConnectionManager是一个更复杂的实现 管理客户端连接池并且能够提供服务 来自多个执行线程的连接请求。连接是 按路线汇总。要求获得的路线 manager已经在池中提供了持久连接 通过租用池中的连接而不是创建来提供服务 一个全新的联系。
PoolingHttpClientConnectionManager保持最大限制 基于每条路线和总共的连接。默认为此 实现将创建不超过2个并发连接 给定路线,总共不再有20个连接。对于许多现实世界 应用这些限制可能会受到限制,特别是如果 他们使用HTTP作为其服务的传输协议。
您可以查看Threaded request execution示例
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);
}
}
}
}