当前位置:编程学习 > JAVA >>

HttpClient多线程的问题

我是这样设置的,单个路由最大连接数设置为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();释放了,难道是线程释放有延时,可也不会要两秒吧(因为后面五个线程访问服务器端,服务器打印信息差不多是两秒一次(但是有时候是一起的,大多数情况是两秒一次),给人的感觉后面五个线程不是并发请求的)这是为什么呢。 --------------------编程问答-------------------- 问题的原因好像就是服务器发出的响应只被一个线程接收了 --------------------编程问答-------------------- 好像是服务器一次就接受一个请求 --------------------编程问答-------------------- 我给你贴个之前一个朋友写的程序。

//直接在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("程序执行结束");
}
}


不晓得你是不是用的线程池。如果是的话,上面这个程序应该可以作个参考。 --------------------编程问答-------------------- 接受请求,就开一个线程。按道理线程运行应该是可以分开的,不用等。 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 额。。不是线程的问题,是没有并发的问题。照道理后面5个线程请求应该是几乎同时的嘛, --------------------编程问答-------------------- 你把你的代码,改成如下,看下测试结果如何,再比较下问题:


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();
}
补充:Java ,  Web 开发
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,