httpClient多线程请求出现超时错误
单线程一次执行一个请求可以正常执行,如果使用多线程,同时执行多个请求时就会出现连接超时
详细代码:
- Java code
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(); } } } }
调用的代码
- Java code
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
[解决办法]
问题应该是出在httpClient上,所有线程共享一个全局的httpClient,这里估计出现资源竞争等待,所以超时了,你有没有试在不用全局的httpClient,而是像httpget一样,每个线程都new一个新的。
[解决办法]
3楼的说法比较有道理。虽然未必是资源竞争等待,但缺省的HttpClient确实不支持并发,这意味很多成员变量在并发使用过程中会互相影响。
如果非要用想某些Cookie信息之类的而不能每个线程独立使用一个HttpClient,建议考虑用 ThreadSafeClientConnManager协助管理,释放方式不复杂,网上也有不少例子。
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager();
cm.setMaxTotal(50);
HttpClient httpclient = new DefaultHttpClient(cm);
[解决办法]
LZ 用我这个 HTTPCLIENT 池试试
- Java code
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); } }}
[解决办法]
好像没加加锁的机制,导致多线程的并发的问题的?