【问题标题】:Java servlet with threads send response to client带有线程的 Java servlet 向客户端发送响应
【发布时间】:2014-07-30 07:55:51
【问题描述】:

我有一个带有 3 个输入字段的 HTML 页面,当用户单击提交按钮时,使用 jQuery 向具有 3 个字段的内容的 servlet 发出 AJAX 请求。

当请求到达服务器(我的servlet)时,我需要为每个输入字段创建一个线程,并管理这个线程池,将它们按顺序排列。
例如;如果线程 1 较早完成,则线程 2 应在下一个线程之前将响应打印给客户端。我目前在每个线程中使用随机睡眠时间的睡眠方法,以确定每个线程应该花费的时间。

在客户端,在 HTML 中,我有一个元素来显示响应。 要将信息发送给客户端,我只需要在 servlet 端调用PrintWriter.write。 我遇到的问题是每个线程的信息同时出现在客户端。
只有在所有线程都完成后,输出才会出现在客户端。 例如;我有线程 a 需要 200 毫秒,线程 b 需要 300 毫秒,线程 c 需要 100 毫秒。 客户端的结果只会在 300 毫秒后出现,例如结果是字符串“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,但结果是一样的。谁能告诉我我做错了什么,为什么线程的结果同时到达客户端?

【问题讨论】:

  • 为什么?您要解决的真正问题是什么?

标签: multithreading servlets


【解决方案1】:

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

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

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

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

事实上,当您在浏览器中看到页面是一块块地出现时,这正是发生的情况:第一次请求 HTML 部分,然后可选地请求其他 css、jsp、图像、视频。

【讨论】:

  • 是的,我需要异步加载信息。我在这里尝试实现的是:而不是客户端向服务器发出多个请求,将它们放在一个列表中,只发出一个请求,然后在服务器端,列表被划分,每个项目成为一个线程,以便可以在每个线程完成时分部分加载信息。是否有可能做到这一点。您有该解决方案的任何示例吗?谢谢
猜你喜欢
  • 1970-01-01
  • 2017-08-11
  • 2013-09-14
  • 1970-01-01
  • 2019-10-22
  • 2016-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多