6

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

根据正常的线程规则,不能保证“发生在”中的实例级字段的分配init(ServeltConfig)会由其他正在执行的线程从相同的字段中读取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 规范。(任何版本,我都很酷)。

4

2 回答 2

7

这在init javadoc中明确说明:

servlet 容器在实例化 servlet 后恰好调用一次 init 方法。init 方法必须成功完成,servlet 才能接收任何请求。

如果您遵循 servlet 生命周期,它表示应该在来自多个线程的请求init之前 -ed一个 servlet。service

于 2013-10-03T11:36:34.883 回答
2

...然后我会有一个线程错误。是什么让容器必然不同?

在您的示例中,init()anddoGet()方法可以重叠。Servlet这在容器中是不可能的。init()容器在开始处理请求之前会注意执行所有调用和其他初始化。跨这些方法边界不存在多线程问题。

您仍然会遇到在doXXX()方法中使用共享日期的问题。

除了查看每个容器的源代码之外,最好的办法是查看(and ) 的javadocServletFilter

该接口定义了初始化 servlet、服务请求以及从服务器中删除 servlet 的方法。这些被称为生命周期方法,并按以下顺序调用:

  • 构建 servlet,然后使用 init 方法进行初始化。
  • 处理来自客户端对服务方法的任何调用。
  • servlet 停止服务,然后使用 destroy 方法销毁,然后进行垃圾收集并完成。

为了真正支持Servlet规范,容器必须遵循这些规则。

这在Servlet 3.0 规范文档Servlet Life Cycle 的第 2.3 章中有描述。

servlet 对象实例化后,容器必须先初始化 servlet,然后才能处理来自客户端的请求。 提供了初始化,以便 servlet 可以读取持久配置数据、初始化昂贵的资源(例如基于 JDBC™ API 的连接)以及执行其他一次性活动。容器通过使用实现 ServletConfig 接口的唯一(每个 servlet 声明)对象调用Servlet 接口的方法来初始化 servlet 实例。init

重要部分以粗体显示

于 2013-10-03T12:48:57.237 回答