Servlet doGet同步 - 不起作用?

时间:2011-05-21 23:45:46

标签: java multithreading servlets synchronized

我知道这是一个简单的问题,但我有些困惑。

如果我理解的话,简单来说,当请求到达Web服务器时,他会为每个请求创建一个线程。

考虑到我们在MyServlet中有下一个代码(我省略了异常处理和类似的代码):

synchronized protected void doGet( ... ...){
    PrintWritet pw=response.getWriter();
    String param=request.getParameter("p");

    if(param.equals("a")){
        wait();
    }else{
        notifyAll();
    }

    pw.write("Hello!");
}

我希望这个servlet会卡住,因为进入此方法的第一个线程(使用param = a)将永远等待,因为任何其他未来的线程将因为synchronized关键字而停留在doGet前面,并且因此notifyAll永远不会被执行。

现在,如果我在浏览器中打开新标签并点击/ MyServlet?p = a,浏览器等待127.0.0.1 ... 之后,我打开新标签并点击/ MyServlet?p = b(或任何!= a)第一个标签被释放并打印出“你好!”信息。

这意味着第二个线程已进入doGet,并执行notifyAll。

为什么会这样?我错过了什么?

1 个答案:

答案 0 :(得分:8)

因为wait()通过输入synchronized块释放之前获得的锁定。来自Object.wait的javadoc:

  

线程释放此监视器的所有权并等待,直到另一个线程通过调用notify方法或notifyAll方法通知等待此对象监视器的线程唤醒。然后该线程等待,直到它可以重新获得监视器的所有权并继续执行。

因此,您的第一个请求获取锁定,输入doGet方法,并调用wait(释放锁定并等待)。第二个请求获取锁定,输入doGet,然后调用notifyAll,这会唤醒第一个请求的主题。

严重您在使用它们之前仔细阅读了waitnotify / notifyAll等方法的文档,或者您将进入麻烦。