我正在为apache-httpclient的httpclient编写测试样本来测试多线程请求错误。
我在for循环中运行它并在每个循环中创建2个线程以运行具有2个不同主机的测试用例设置为池化管理器。
在10个循环中,我总是遇到1个错误: 线程中的异常"线程-2" java.lang.IllegalStateException:条目[id:17] [route:{} - > http:// ***:8000] [state:null]尚未从此池中租借 在org.apache.http.util.Asserts.check(Asserts.java:46)
我的代码有问题吗?我该怎么办?
样本如下:
private void testHttpClient() {
HttpHost proxy = new HttpHost("dev.host.com", 8001);
final DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
final PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(20);
cm.setDefaultMaxPerRoute(1);
HttpHost localhost1 = new HttpHost("dev.test1.com", 8001);
cm.setMaxPerRoute(new HttpRoute(localhost1), 2);
HttpHost localhost2 = new HttpHost("dev.test2.com", 8000);
cm.setMaxPerRoute(new HttpRoute(localhost2), 2);
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(1000)
.setSocketTimeout(1000)
.setConnectionRequestTimeout(1000)
.build();
final CloseableHttpClient httpclient1 = HttpClients.custom()
.setConnectionManager(cm)
.setRoutePlanner(routePlanner)
.setDefaultRequestConfig(requestConfig)
.build();
RequestConfig requestConfig2 = RequestConfig.custom()
.setConnectTimeout(1000)
.setSocketTimeout(1000)
.setConnectionRequestTimeout(1000)
.build();
final CloseableHttpClient httpclient2 = HttpClients.custom()
.setConnectionManager(cm)
.setRoutePlanner(routePlanner)
.setDefaultRequestConfig(requestConfig2)
.build();
class HttpClientThead1 implements Runnable {
public void run() {
for (int i = 1; i <= 1; i++) {
System.out.println("HttpClientThead1 Start");
HttpClientContext context = HttpClientContext.create();
try {
HttpGet httpget = new HttpGet("http://dev.test1.com:8001/test/id/10001");
CloseableHttpResponse response = httpclient1.execute(httpget, context);
long t = System.currentTimeMillis();
System.out.println("HttpClientThead1 " + i + ":" + response.getEntity().toString() + " " + t);
response.close();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
cm.closeExpiredConnections();
cm.closeIdleConnections(30, TimeUnit.SECONDS);
}
}
}
}
class HttpClientThead2 implements Runnable {
public void run() {
for (int i = 1; i <= 1; i++) {
System.out.println("HttpClientThead2 Start");
HttpClientContext context = HttpClientContext.create();
try {
HttpGet httpget2 = new HttpGet("http://dev.test2.com:8000/test/id/10002");
CloseableHttpResponse response2 = httpclient2.execute(httpget2, context);
long t = System.currentTimeMillis();
System.out.println("HttpClientThead2 " + i + ":" + response2.getEntity().toString() + " " + t);
response2.close();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
cm.closeExpiredConnections();
cm.closeIdleConnections(30, TimeUnit.SECONDS);
}
}
}
}
for (int j = 1; j <= 10; j++) {
HttpClientThead1 t1 = new HttpClientThead1();
HttpClientThead2 t2 = new HttpClientThead2();
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.start();
thread2.start();
}
}
答案 0 :(得分:0)
我得到了答案,因为我在这个httpclient中设置了一个代理。 所以我还需要用代理信息将它设置为setMaxPerRoute。
所以它应该是: cm.setMaxPerRoute(new HttpRoute(localhost2,proxy),10);
答案 1 :(得分:0)
我相信您在HttpClient中发现了一个错误;我在这里报告了该问题:https://issues.apache.org/jira/browse/HTTPCORE-634。仅在使用连接池但不重用连接时会发生这种情况。
仅当整个响应都用完后,才能重新使用Http连接。我将您的代码更改如下:
(...)
CloseableHttpResponse response2 = httpclient2.execute(httpget2, context);
HttpEntity entity = response.getEntity();
// consume the response
EntityUtils.consumeQuietly(entity);
response2.close();
(...)
,此后没有失败。因此,要么使用响应,要么不使用连接池,就可以了。