我想知道为什么调用javax.servlet.Servlet#getServletConfig()
是线程安全的:如果你检查实现从servlet API 3.0.1获取javax.servlet.GenericServlet
,您可以看到以下内容:
package javax.servlet;
// lines omitted
public abstract class GenericServlet
implements Servlet, ServletConfig, java.io.Serializable
{
// lines omitted
private transient ServletConfig config;
// lines omitted
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
// lines omitted
public ServletConfig getServletConfig() {
return config;
}
// lines omitted
}
字段config
在init(ServletConfig)
中写入,没有任何同步,锁定或config
是易失的,而getServletConfig()
可以随时从servlet容器的任何后续工作线程调用。我快速查看了Tomcat/Catalina代码库,但是我没有看到servlet容器执行任何魔术的迹象,这将保证线程安全访问字段config
到getServletConfig()
,例如javax.servlet.GenericServlet#service(ServletRequest, ServletResponse)
和javax.servlet.http.HttpServlet
中的相应方法。
我错过了什么吗?如果线程A被用于init(ServletConfig)
,那么线程B调用getServletConfig()
将会看到字段config
的正确状态(Java "happens-before"),而不是例如null
?
ServletConfig
是一个单例对象(由容器管理),您仅使用它来检索init-parameters
或在servlet init
阶段获取servletcontext
或servletname集。你不能写任何东西到ServletConfig
对象,而容器单独管理这个对象,所以,它是线程安全的。
字段配置在init(ServletConfig)中写入,没有任何同步,锁定或配置不稳定,而getServletConfig()可以随时从servlet容器的任何后续工作线程调用?
GenericServlet
是一个抽象类,容器不会为其创建任何对象,而是为您编写/提供的自定义HttpServlet
类创建一个对象(默认只有一个实例),通过该对象初始化ServletConfig
对象。
这个问题是关于getServletConfig
()的线程安全性,而不是ServletConfig
?
一旦容器在servlet生命周期的init
阶段创建了ServletConfig
对象,它就永远不会被更改。因此,getServletConfig
()是线程安全的(也就是说,不管有多少线程读取ServletConfig
对象,只要不允许任何线程向其写入任何内容)。
更新问题:
如果线程A被用来init(ServletConfig)然后线程B调用getServletConfig()将看到正确的状态字段配置(Java"happens-before"),而不是例如null?
servlet容器在实例化servlet之后只调用一次init方法。 init方法必须成功完成,servlet才能接收任何请求。如果init方法抛出ServletException或在Web服务器定义的时间段内没有返回,servlet容器就不能将servlet放入服务中。你可以看这里
用户请求线程的创建只有在init()方法成功完成后才会发生。因此,不需要在用户请求线程之间进行数据(servletconfig
)同步,因为 servletconfig
对象甚至在用户请求线程创建之前就已经可用了。