带有线程的Java servlet向客户端发送响应

时间:2014-07-30 07:55:51

标签: multithreading servlets

我有一个包含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,但结果是相同的。谁能告诉我我做错了什么,为什么线程的结果同时到达客户端?

1 个答案:

答案 0 :(得分:0)

无论你在servlet中做什么,你都在客户端,浏览器和服务器,java应用程序之间使用HTTP协议。

protocole说:浏览器准备并发送请求,服务器获取请求,并详细说明并发送响应:每个请求一个响应。

三个线程写入相同的响应。希望你的3个线程一次运行一个,每个线程对响应写入很少,如果不是,你可以混合使用线程输出。并且你的servlet请等待线程的结束终止,否则servlet容器会在线程有时间写任何东西之前关闭响应。

你没有说出你想要实现的目标,我想你想测试异步加载信息。为此,您需要多个请求:一个用于初始化操作,一个用于每条信息,servlet使用会话来注册它已传输的内容和剩余的内容,或者客户端识别它想要的部分。但是详细的工作远远超出了我在这个答案中所能提出的内容......

事实上,当你在浏览器中看到逐页出现的页面时,它正是发生的事情:对HTML部分的第一次请求,然后是css,jsp,图像,视频的其他选择。