Servlet规范规定,容器将实例化我的java.servlet.HttpServlet的单个实例,并从多个工作线程中调用服务方法(doGet() / doPost())。

根据正常的线程规则,不能保证init(ServeltConfig)“happen before”中实例级字段的分配被其他执行doGet()的线程从相同的字段中读取,除非有人在某个时候安排了同步。

容器实际上可能确实在进行某种外部同步,以确保init()中完成的工作对“后续”线程可见。

但是,Servlet规范是否明确保证我是线程安全的?尽管我必须承认,但我现在还找不到这样的保证,自Servlet 2.4以来,我还没有从端到端阅读规范。

编辑

例如,由于一些回答者正在把事情弄混,所以我的问题是:关于Servlet规范说什么是下一个类是线程安全的?

@WebServlet (initParams = {@WebInitParam(name="b", value="true")})
public Decider extends HttpServlet {

    private boolean b = false;

    public void init(ServletConfig config) {
        this.b = Boolean.parseBoolean(config.getAttribute("b"));
    }

    public void doGet(HttpServletRequest req, HttpServletResponse res) {
        res.sendRedirect(b ? "/true" ? "/false");
    }

}

当然,如果我要这样做:
public static void main(String[] argv) {

      HttpServlet s = new Decider();

      Thread t1 = new Thread(new Runnable() {
        public void run() {
            s.init(...);
        }
      });

      Thread t2 = new Thread(new Runnable() {
        public void run() {
            s.doGet(...);
        }
      });

      t1.start();
      t2.start();
}

...那么我会有一个线程错误。是什么使容器必然与众不同?

编辑2

肯定有人欢迎所有断言“容器能解决这一问题”,但是我的问题是关于Servlet规范是否能保证这种行为。为了充分回答这个问题,您必须参考Servlet规范。 (任何版本,我都很酷)。

最佳答案

这在init javadoc中明确指出:

servlet容器恰好在调用完一次init方法之后
实例化servlet。初始化方法必须成功完成
servlet可以接收任何请求之前。

而且,如果您遵循Servlet生命周期,则表示在从多个线程请求init之前,应先对servlet进行service编码。

07-24 09:49
查看更多