如果我在HttpServlet#init(ServletConfig)中分配实例字段,Servlet规范是否保证我可以在doGet()中读取它们?

7 浏览
0 Comments

如果我在HttpServlet#init(ServletConfig)中分配实例字段,Servlet规范是否保证我可以在doGet()中读取它们?

Servlet规范规定,容器将实例化一个java.servlet.HttpServlet的单一实例,并从多个工作线程中调用服务方法(doGet()/doPost())。\n根据正常的线程规则,在init(ServeltConfig)中对实例级别字段进行赋值,并不能保证在其他执行doGet()的线程读取这些字段之前“发生”,除非有人在某个时刻进行同步。\n可能,容器确实会进行某种外部同步,以确保在init()中完成的工作对“后续”线程可见。\n然而,Servlet规范是否明确保证我是线程安全的?我刚才没有找到这样的保证,尽管我必须承认,自Servlet 2.4以来,我还没有从头到尾阅读过规范。\n编辑\n例如,由于一些回答者搞混了一些事情,我的问题是:Servlet规范中的哪一部分说明了以下类是线程安全的?\n

@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");
    }
}

\n当然,如果我这样做:\n

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();
}

\n...那么我将有一个线程错误。容器有什么不同呢?\n编辑2\n所有声称“容器会处理这个问题”的答案当然是受欢迎的,但我的问题特别是关于Servlet规范是否保证了这种行为。要充分回答这个问题,你必须参考Servlet规范。(任何版本都可以,我没问题)。

0
0 Comments

问题的出现原因是在Servlet中,如果在init()方法中给实例字段赋值,能否在doGet()方法中读取它们。解决方法是查看Servlet规范文档来了解Servlet的生命周期方法调用顺序,以及容器必须按照规范来实现这些方法。Servlet规范规定了容器必须在处理请求之前先完成所有的初始化操作,因此在init()方法中给实例字段赋值是安全的。下面是根据提供的内容整理的文章:

在Servlet中,如果在init()方法中给实例字段赋值,能否在doGet()方法中读取它们?这个问题的出现源于对Servlet的生命周期方法调用顺序的疑问。解决方法是查看Servlet规范文档来了解Servlet的生命周期方法调用顺序,以及容器必须按照规范来实现这些方法。

在给定的例子中,init()方法和doGet()方法可能会重叠。但是在Servlet容器中,这是不可能发生的。容器会在开始处理请求之前完成所有的初始化操作。因此,在这两个方法之间不存在多线程问题。

然而,在doXXX()方法中使用共享数据仍然会存在问题。

要真正支持Servlet规范,容器必须遵循规范规定的顺序执行这些方法。

Servlet的生命周期在Servlet 3.0规范文档的第2.3章节中进行了描述。文档中指出,在Servlet对象实例化之后,容器必须在处理客户端请求之前初始化Servlet。初始化过程用于读取持久化配置数据、初始化昂贵的资源(如基于JDBC的连接)以及执行其他一次性活动。容器通过调用Servlet接口的init()方法来初始化Servlet实例。

通过查看Servlet规范文档,我们可以确定容器必须按照规范来执行这些方法。

因此,要回答这个问题,只需要指出规范规定了容器必须按照规定的顺序调用这些方法即可。

Servlet规范是您能够得到的最好的答案。

0
0 Comments

问题的出现原因是在Servlet规范中,它明确规定servlet容器在实例化servlet后会调用init方法,并且在servlet能够接收任何请求之前,init方法必须成功完成。此外,根据servlet的生命周期,servlet应该在从多个线程接收服务请求之前进行初始化。

然而,问题在于init()方法将在Web应用程序启动时由某个线程调用,而doGet()方法将在服务器的线程池中的任何其他线程中调用。那么,谁负责确保实例字段的安全发布?

对此问题,有一个回答是通过在init方法中将实例字段标记为volatile。通过这种方式,可以假设GenericServlet是根据此方式实现的。

从规范的角度来看,我认为"complete successfully *before*"可以理解为正式的"happens-before"关系。

0