我有一个包含3个输入字段的HTML页面,当用户单击提交按钮时,使用jQuery向具有3个字段的conetnts的servlet发出AJAX请求。
当请求到达服务器(我的servlet)时,我需要为每个输入字段创建一个线程,并管理这个线程池,将它们按顺序排列。
例如;如果线程1更早完成,则线程2应在下一个线程之前将响应打印到客户端。我目前正在每个线程中使用一个随机休眠时间的睡眠方法,以确定每个线程应该采取的时间。
在客户端,在HTML中,我有一个显示响应的元素。
要将信息发送到客户端,我只需要在servlet端调用PrintWriter.write
。
我遇到的问题是每个线程的信息同时出现在客户端
所有线程完成后,输出仅出现在客户端。
例如;我有一个花了200毫秒的线程,一个花了300毫秒的线程b和一个花了100毫秒的线程c。
客户端的结果仅在300ms后出现,例如结果将是字符串“cab”。
所以我的HTML页面上有以下JavaScript函数:
$.ajax({
type : 'get',
url : 'ServletResponse2',
data : {
"name1" : name1,"name2" : name2, "name3" : name3
},
success : function(xhr,data) {
console.log("xhr:"+xhr);
console.log("xhr text:"+xhr.responseText);
console.log("data:"+data);
console.log("data2:"+data.data);
$("#listResponse2").append("<li>" + xhr);
$("#listResponse2").append("</li>");
},
complete : function(xhr,data) {
response = xhr.responseText;
console.log("exception:"+response);
$("#listResponse").append("<li>" + response);
$("#listResponse").append("</li>");
},
error : function(e) {
console.log("exception:"+e);
}
});
然后,在servlet中,我有这个get方法调用一个执行器服务,它调用一个实现Runnable
的类工作线程:
protected void doGet(HttpServletRequest request,HttpServletResponse response)
{
ExecutorService executor= Executors.newFixedThreadPool(3);
PrintWriter out=null;
response.setCharacterEncoding("UTF-8");
String name1 = request.getParameter("name1");
String name2 = request.getParameter("name2");
String name3 = request.getParameter("name3");
String name="";
for (int i = 1; i < 4; i++) {
name=request.getParameter("name"+i);
try {
out = response.getWriter();
Runnable worker = new WorkerThread("" + name,response);
executor.execute(worker);
} catch (IOException e) {
e.printStackTrace();
}
}
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("Finished all threads");
out.print(name);
}
在WorkerThread.java
中,我创建了一个run()
方法,该方法正在为每个servlet编写响应,我甚至使用了out.flush()
和response.flushbuffer()
方法。
public class WorkerThread implements Runnable {
private String command;
PrintWriter out;
HttpServletResponse response;
public WorkerThread(String s,HttpServletResponse sresponse){
this.command=s;
this.response=sresponse;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" Start. Command = "+command);
try {
out = response.getWriter();
out.write(command);
out.flush();
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
}
processCommand();
System.out.println(Thread.currentThread().getName()+" End.");
}
private void processCommand() {
try {
Long time=(long)(Math.random() * 5000);
Thread.sleep(time);
System.out.println("Thread.getName():"+Thread.currentThread().getName()+"|comand:"+command+"|time:"+ time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString(){
return this.command;
}
}
我还尝试在执行程序服务中使用Callabe
而不是Runnable
,但结果是相同的。谁能告诉我我做错了什么,为什么线程的结果同时到达客户端?
答案 0 :(得分:0)
无论你在servlet中做什么,你都在客户端,浏览器和服务器,java应用程序之间使用HTTP协议。
protocole说:浏览器准备并发送请求,服务器获取请求,并详细说明并发送响应:每个请求一个响应。
三个线程写入相同的响应。希望你的3个线程一次运行一个,每个线程对响应写入很少,如果不是,你可以混合使用线程输出。并且你的servlet请等待线程的结束终止,否则servlet容器会在线程有时间写任何东西之前关闭响应。
你没有说出你想要实现的目标,我想你想测试异步加载信息。为此,您需要多个请求:一个用于初始化操作,一个用于每条信息,servlet使用会话来注册它已传输的内容和剩余的内容,或者客户端识别它想要的部分。但是详细的工作远远超出了我在这个答案中所能提出的内容......
事实上,当你在浏览器中看到逐页出现的页面时,它正是发生的事情:对HTML部分的第一次请求,然后是css,jsp,图像,视频的其他选择。