【问题标题】:Thread-safety of javax.servlet.Servlet#getServletConfig()javax.servlet.Servlet#getServletConfig() 的线程安全
【发布时间】:2017-03-21 23:46:03
【问题描述】:

我想知道为什么调用javax.servlet.Servlet#getServletConfig() 是线程安全的:如果您检查实现 javax.servlet.GenericServlet 来自 servlet API 3.0.1,您会看到以下内容:

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 容器执行任何魔法的迹象,这将保证线程安全访问字段 configgetServletConfig(),例如javax.servlet.GenericServlet#service(ServletRequest, ServletResponse)javax.servlet.http.HttpServlet中的对应方法。

我在这里遗漏了什么吗?什么可以保证如果线程 A 用于 init(ServletConfig),那么调用 getServletConfig() 的线程 B 将看到字段 config 的正确状态(Java “happens-before”),而不是例如null?

【问题讨论】:

    标签: java multithreading tomcat servlets thread-safety


    【解决方案1】:

    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“之前发生”),而不是例如空?

    servlet 容器在实例化 servlet 后恰好调用一次 init 方法。 init 方法必须成功完成,servlet 才能接收任何请求。 如果 init 方法抛出 ServletException 或未在 Web 服务器定义的时间段内返回,则 servlet 容器无法将 servlet 投入使用。可以看here

    用户请求线程的创建仅在 init() 方法成功完成后发生。因此,用户请求线程之间不需要数据 (servletconfig) 同步,因为servletconfig 对象在创建用户请求线程之前就已经可用

    【讨论】:

    • 问题是关于getServletConfig() 的线程安全,而不是ServletConfig
    • 是的,这是关于字段的可见性:扩展问题在这里更清楚。
    • 添加了解释,让我知道你需要更清楚这一点
    • @javaguy 理论上getServletConfig() 可以在一个线程中初始化后继续从其他线程返回null,因为没有采取任何步骤来确保对其他线程的可见性(例如具有 volatile 字段或同步方法)。创建后不改变也没关系。
    • @javaguy 答案仍然没有解决来自不同线程的分配对其他线程不一定可见的问题,除非采取措施确保它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 2022-11-21
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    • 2015-06-01
    相关资源
    最近更新 更多