httpClient多线程请求出现超时错误

sknice 2012-10-25 11:48:06
单线程一次执行一个请求可以正常执行,如果使用多线程,同时执行多个请求时就会出现连接超时
详细代码:

package generate.httpclient;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

public class ThreadPoolHttpClient {
// 线程池
private ExecutorService exe = null;
// 线程池的容量
private static final int POOL_SIZE = 20;
private HttpClient client = null;
String[] urls=null;
public ThreadPoolHttpClient(String[] urls){
this.urls=urls;
}
public void test() throws Exception {
exe = Executors.newFixedThreadPool(POOL_SIZE);
HttpParams params =new BasicHttpParams();
/* 从连接池中取连接的超时时间 */
ConnManagerParams.setTimeout(params, 1000);
/* 连接超时 */
HttpConnectionParams.setConnectionTimeout(params, 2000);
/* 请求超时 */
HttpConnectionParams.setSoTimeout(params, 4000);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(
new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));

//ClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry);
PoolingClientConnectionManager cm=new PoolingClientConnectionManager(schemeRegistry);
cm.setMaxTotal(10);
final HttpClient httpClient = new DefaultHttpClient(cm,params);

// URIs to perform GETs on
final String[] urisToGet = urls;
/* 有多少url创建多少线程,url多时机子撑不住
// 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);
}
// 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();
}
使用线程池*/
for (int i = 0; i < urisToGet.length; i++) {
final int j=i;
System.out.println(j);
HttpGet httpget = new HttpGet(urisToGet[i]);
exe.execute( new GetThread(httpClient, httpget));
}


//创建线程池,每次调用POOL_SIZE
/*
for (int i = 0; i < urisToGet.length; i++) {
final int j=i;
System.out.println(j);
exe.execute(new Thread() {
@Override
public void run() {
this.setName("threadsPoolClient"+j);

try {
this.sleep(100);
System.out.println(j);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

HttpGet httpget = new HttpGet(urisToGet[j]);
new GetThread(httpClient, httpget).get();
}



});
}

*/
//exe.shutdown();
System.out.println("Done");
}
static class GetThread extends Thread{

private final HttpClient httpClient;
private final HttpContext context;
private final HttpGet httpget;

public GetThread(HttpClient httpClient, HttpGet httpget) {
this.httpClient = httpClient;
this.context = new BasicHttpContext();
this.httpget = httpget;
}
@Override
public void run(){
this.setName("threadsPoolClient");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
get();
}

public void get() {
try {
HttpResponse response = this.httpClient.execute(this.httpget, this.context);
HttpEntity entity = response.getEntity();
if (entity != null) {
System.out.println(this.httpget.getURI()+": status"+response.getStatusLine().toString());
}
// ensure the connection gets released to the manager
EntityUtils.consume(entity);
} catch (Exception ex) {
this.httpget.abort();
}finally{
httpget.releaseConnection();
}
}
}
}

调用的代码

String[] urls = new String[20];
for(int i=1;i<21;i++)
{
String str = "http://"
+ "192.168.1."+i
+ "/web/getwinoptions.php?opt=2.59,3.53,3.54,2.56,3.57,3.58,3.61,3.62,3.63,3.64,3.55,3.59,&ts=1331929083";
urls[i-1]=str;
}
ThreadPoolHttpClient pool = new ThreadPoolHttpClient(urls);
pool.test();

执行的url都是有效的,单个执行或者在浏览器上打开时都没有问题,但是同时执行时就会超时
参考资料:
http://www.cnblogs.com/wasp520/archive/2012/06/28/2568897.html
...全文
1933 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
zd10101501 2013-11-22
  • 打赏
  • 举报
回复
我今天也遇到了,原因是你请求的是同一个服务器下的不同页面,httpclient在你和服务器之间建立了一条路由,这个路由的最大并发连接数是2,所以当你开启多个线程并发请求的时候,就会出现连接不够用或者连接超时的问题,解决方法是这样的(红色为重点): HttpParams params = new BasicHttpParams(); /* 从连接池中取连接的超时时间 */ ConnManagerParams.setTimeout(params, 10000); /* 连接超时 */ HttpConnectionParams.setConnectionTimeout(params, 20000); /* 请求超时 */ HttpConnectionParams.setSoTimeout(params, 40000); SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory .getSocketFactory())); PoolingClientConnectionManager cm = new PoolingClientConnectionManager( schemeRegistry); cm.setMaxTotal(10); HttpHost localhost = new HttpHost("locahost", 80); cm.setMaxPerRoute(new HttpRoute(localhost), 50); cm.setDefaultMaxPerRoute(20); final HttpClient httpClient = new DefaultHttpClient(cm, params);
Kanepan 2012-10-25
  • 打赏
  • 举报
回复
LZ 用我这个 HTTPCLIENT 池试试


package com.kanesoft.method.httppost;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;

public class MultiThreadedHttpConnection {
private static HttpClient httpClient;
private static final String contextType = "text/xml;charset=UTF-8";
private static ExecutorService es = Executors.newFixedThreadPool(10);
private static MultiThreadedHttpConnection mthc = new MultiThreadedHttpConnection();
private static String url = "http://localhost:8000/2.php";
private static int maxTotal = 300;
private static int maxPerRout = 200;
private static int connecttimeOut = 10000;
private static int readTimeOut = 5000;

static {
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager();
cm.setMaxTotal(maxTotal);
cm.setDefaultMaxPerRoute(maxPerRout);

HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, connecttimeOut);
HttpConnectionParams.setSoTimeout(params, readTimeOut);

httpClient = new DefaultHttpClient(cm, params);

}

private MultiThreadedHttpConnection() {

}

public static MultiThreadedHttpConnection getInstance() {
return mthc;
}

public void httpAsyncSendByMap(final Map<String, String> map) {
es.execute(new postThread(mthc, map));
}

private int sendDataByPost(Map<String, String> map) {
Integer statusCode = -1;
HttpPost post = new HttpPost(url);
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
for (Map.Entry<String, String> m : map.entrySet()) {
nvps.add(new BasicNameValuePair(m.getKey(), m.getValue()));
}
StringEntity entity;
try {
entity = new UrlEncodedFormEntity(nvps, HTTP.UTF_8);
post.setEntity(entity);
post.setHeader("Content-Type", contextType);
HttpResponse response = httpClient.execute(post);
statusCode = response.getStatusLine().getStatusCode();
System.out.println(statusCode);
if (statusCode != 200) {
System.out.println("error quest");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
post.abort();
}

return statusCode;
}

class postThread implements Runnable {
private MultiThreadedHttpConnection m = null;
private Map<String, String> map = null;

public postThread(MultiThreadedHttpConnection m, Map<String, String> map) {
this.m = m;
this.map = map;
}

@Override
public void run() {
m.sendDataByPost(map);
}
}

public static void main(String[] args) {
for (int i = 0; i < 10000; i++) {
Map<String, String> map = new HashMap<String, String>();
map.put("vcode", 1 + "");
map.put("sid", i + "");
MultiThreadedHttpConnection.getInstance().httpAsyncSendByMap(map);
}
}
}

MiceRice 2012-10-25
  • 打赏
  • 举报
回复
3楼的说法比较有道理。虽然未必是资源竞争等待,但缺省的HttpClient确实不支持并发,这意味很多成员变量在并发使用过程中会互相影响。

如果非要用想某些Cookie信息之类的而不能每个线程独立使用一个HttpClient,建议考虑用 ThreadSafeClientConnManager协助管理,释放方式不复杂,网上也有不少例子。

ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager();
cm.setMaxTotal(50);
HttpClient httpclient = new DefaultHttpClient(cm);
zxhcloth 2012-10-25
  • 打赏
  • 举报
回复
问题应该是出在httpClient上,所有线程共享一个全局的httpClient,这里估计出现资源竞争等待,所以超时了,你有没有试在不用全局的httpClient,而是像httpget一样,每个线程都new一个新的。
sknice 2012-10-25
  • 打赏
  • 举报
回复
MiceRice 2012-10-25
  • 打赏
  • 举报
回复
超时数量大不大?如果只有2、3个,其实可能是正常的。
你有时候在浏览器同时打开多个页面,也会有个别页面会被卡住了。
chenlian103323 2012-10-25
  • 打赏
  • 举报
回复
好像没加加锁的机制,导致多线程的并发的问题的?
sknice 2012-10-25
  • 打赏
  • 举报
回复
每个线程单独使用 HttpClient 一样超时。

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧