读书人

httpClient多线程请求出现超时异常

发布时间: 2012-11-03 10:57:44 作者: rapoo

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);        }    }} 


[解决办法]
好像没加加锁的机制,导致多线程的并发的问题的?

读书人网 >J2SE开发

热点推荐