我是这样设置的,单个路由最大连接数设置为5,其他获取连接延时、读取、请求、总连接数都是设置的很大,然后我在服务器端设置了一个响应延时2秒,问题是:
for(int i=1;i<=10;i++){
HttpGet get=new HttpGet("http://localhost:8080/AA/servlet/s");
new Thread(new RequestThread(get,client)).start();
}
如上,我直接起10个线程发出请求,由于单个路由最大连接数设置为5,所以先发了五个请求,其余五个在等待,我在服务端加了个输出信息,两秒过后,服务器后台基本是同时打印了5个输出信息,这边我没什么问题,问题是,这五个线程完了直后,应该是等待的那五个线程开始执行了,但是我看服务器端打印输出信息是一个一个打印出来的,我很奇怪,难道剩下来的5个线程不是几乎同时执行的吗,前面5个线程我已经method.releaseConnection();释放了,难道是线程释放有延时,可也不会要两秒吧(因为后面五个线程访问服务器端,服务器打印信息差不多是两秒一次(但是有时候是一起的,大多数情况是两秒一次),给人的感觉后面五个线程不是并发请求的)这是为什么呢。

解决方案 »

  1.   

    我给你贴个之前一个朋友写的程序。//直接在MyEclipse里执行,即可看到问题所在。
    //线程是一个一个运行的。执行一个线程,执行完毕之后才会执行新的线程。
    //所以才会出现程序运行时间为“所有线程之和”。import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;public class GetPnrPriceHandler implements Callable<String> {
    private String key;
    private String value;
    static private int i; public GetPnrPriceHandler(String key, String value) {
    this.key = key;
    this.value = value;
    } @Override
    public String call() throws Exception {
    i ++;
    System.out.println("执行线程" + i);
    Thread.sleep(2000 * i);
    String result = "temp";
    System.out.println("线程执行结束" + i);
    return result;
    } // 传入一个map对象,其中为?的数据
    // 程序运行过程中,使用线程池,运行多个线程。
    // 返回一个map对象,其中保存的是?的数据。
    public static Map<String, String> avResults(
    Map<String, String> queryParamLst) throws InterruptedException,
    ExecutionException {
    Map<String, String> resxml = new HashMap<String, String>();
    // 创建一个线程池
    ExecutorService pool = Executors.newFixedThreadPool(5);

    // 循环多次,次数为Map对象queryParamLst中存放的项目数。
    for (String key : queryParamLst.keySet()) {
    // 将queryParamLst中相关String取出,包装为Callable对象。
    Callable<String> c = new GetPnrPriceHandler(key, queryParamLst
    .get(key));
    // 启动单个线程
    Future<String> future = pool.submit(c);
    // 线程运行结束,获取其结果
    String res = future.get();
    // 将结果放到resxml中保存
    resxml.put(key, res.toString());
    }
    pool.shutdown();
    return resxml;
    }

    public static void main(String[] args) {
    Map<String, String> queryParamLst = new HashMap<String, String>();
    queryParamLst.put("1","100");
    queryParamLst.put("2","100");
    queryParamLst.put("3","100");
    try {
    avResults(queryParamLst);
    } catch (InterruptedException e) {
    e.printStackTrace();
    } catch (ExecutionException e) {
    e.printStackTrace();
    }
    }
    }
    我给他改过来,程序如下:import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.Callable;
    import java.util.concurrent.CompletionService;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorCompletionService;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;public class GetPnrPriceHandler implements Callable<String[]> {
    private String key;
    private String value;
    static private int j = 1;
    private int i; public GetPnrPriceHandler(String key, String value) {
    this.key = key;
    this.value = value;
    i = j;
    j++;
    } @Override
    public String[] call() throws Exception {
    System.out.println("执行线程" + i);
    Thread.sleep(2000 * i);
    String[] result = new String[2];
    result[0] = "result" + i;
    System.out.println("线程执行结束" + i);
    // 将线程的key放入到result中。
    result[1] = key;
    return result;
    } // 传入一个map对象,其中为?的数据
    // 程序运行过程中,使用线程池,运行多个线程。
    // 返回一个map对象,其中保存的是?的数据。
    public static Map<String, String> avResults(
    Map<String, String> queryParamLst) throws InterruptedException,
    ExecutionException {
    Map<String, String> resxml = new HashMap<String, String>();
    // 创建一个线程池
    ExecutorService pool = Executors.newFixedThreadPool(5);
    // 创建CompletionService实例。CompletionService对线程池又进行了一层包装,可以执行多个方法。
    CompletionService<String[]> completionService = new ExecutorCompletionService<String[]>(
    pool); // 循环多次,次数为Map对象queryParamLst中存放的项目数。
    for (String key : queryParamLst.keySet()) {
    // System.out.println("key----" + key);
    // 将queryParamLst中相关String取出,包装为Callable对象。
    Callable<String[]> c = new GetPnrPriceHandler(key, queryParamLst
    .get(key));
    // 启动单个线程。直接使用completionService.submit(c)就会启动一个线程。
    completionService.submit(c); // 问题出在这几句话。不应该等待其运行结束。
    // 线程运行结束,获取其结果
    // String res = future.get();
    // 将结果放到resxml中保存
    // resxml.put(key, res.toString());
    // 解决方案就是把这两句放到for循环外面。
    } System.out.println("for循环结束!"); // 使用循环,等待结果出现,然后获取结果。
    boolean overFlag = false;
    while (!overFlag) {
    // 从completionService中获取结果。
    Future<String[]> future = completionService.take();
    // 注意,future.get()方法为阻塞性方法。若没有结果,将一直等待。
    String[] res = future.get(); // 如果不是阻塞性方法,那么下面这个打印将不停打印(因while循环所致)
    // 但因为future.get();是阻塞性方法
    // 没有结果将一直等待,获取到一个结果之后才会执行下面的语句。
    System.out.println("获取到一个结果!" + res[0]); // res中包含result与key值,需要进行拆分,形成一个String数组。
    // res[0]为result,[1]为key。
    String threadRes = res[0];
    String threadKey = res[1]; // 将结果集放到resxml中。
    // System.out.println("threadRes----" + threadRes);
    // System.out.println("threadKey----" + threadKey);
    resxml.put(threadKey, threadRes); // System.out.println("resxml.size() = "
    // + resxml.size());
    // System.out.println("queryParamLst.size() = "
    // + queryParamLst.size()); // 若resxml中项目数量达到启动的线程数,overFlag = true,终止循环。
    if (resxml.size() == queryParamLst.size()) {
    overFlag = true;
    }
    } pool.shutdown();
    return resxml;
    } public static void main(String[] args) {
    Map<String, String> queryParamLst = new HashMap<String, String>();
    queryParamLst.put("1", "100");
    queryParamLst.put("2", "100");
    queryParamLst.put("3", "100");
    try {
    avResults(queryParamLst);
    } catch (InterruptedException e) {
    e.printStackTrace();
    } catch (ExecutionException e) {
    e.printStackTrace();
    }
    System.out.println("程序执行结束");
    }
    }
    不晓得你是不是用的线程池。如果是的话,上面这个程序应该可以作个参考。
      

  2.   

    你把你的代码,改成如下,看下测试结果如何,再比较下问题:
    for(int i=1;i<=5;i++){
    HttpGet get=new HttpGet("http://localhost:8080/AA/servlet/s");
    new Thread(new RequestThread(get,client)).start();
    }
    for(int i=1;i<=5;i++){
    HttpGet get=new HttpGet("http://localhost:8080/AA/servlet/s");
    new Thread(new RequestThread(get,client)).start();
    }