【问题标题】:Servlet init method having synchronized block具有同步块的 Servlet 初始化方法
【发布时间】:2013-05-08 09:10:38
【问题描述】:

我有一个问题。在我的应用程序中,我有一个 servlet,其初始化代码如下。

public class GameInitServlet extends HttpServlet {

private static boolean initialized = false;

 @Override
    public void init() throws ServletException {
        // This is a safeguard against running init() more than once.
        synchronized (GameInitServlet.class) {
            if (initialized) {

                LOG.error("GameInitServlet has already been initialized... Bailing out!");
                return;
            }
            initialized = true;
        }
        //some code here....
    }
}

注意:在 web.xml 中 上面的 servlet 的 load-on-startup 为 1,所以它会在应用启动时被初始化。

所以我的问题是为什么我们要同步 init 方法。毕竟它将由 servlet 容器处理,并且只被调用一次。 能不能把上面的同步过程去掉,不然去掉后会对应用有一些影响。

【问题讨论】:

标签: java servlets


【解决方案1】:

init()只执行一次,当 Servlet 最初在其将创建的单个实例上加载到容器中时。然后doGet()doPost() 方法将为每个请求作为单独的执行线程执行。我看不到同步init() 方法或其中的任何代码的任何点。即使在分布式环境中,每个 JVM 也可能有一个 Servlet 实例。我认为容器足够明智,在 Servlet 的生命周期内只调用一次 init(),因此多个线程之间不会有任何争用执行init()。根据Javadocs

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

【讨论】:

    【解决方案2】:

    正如评论所说

    // This is a safeguard against running init() more than once.
    

    这只是试图保存某种不应该发生的竞争条件。

    任何 Servlet、Filter 和 Listener 的生命周期与 webapp 的生命周期一样长。它们在所有会话中的所有请求之间共享。

    所以你可以说 init() 方法在容器中被调用一次。所以不需要有同步块。

    但是,您是在类级别而不是在对象级别锁定,有什么相同的原因吗?您应该检查任何同步的静态调用,这可能是有这个块的正当理由。如果没有,您可以删除它。

    你可以看到一些很好的解释here

    【讨论】:

      【解决方案3】:

      总的来说,我同意您的评价。

      它似乎没有实现单线程,因此删除“同步”不应该受到伤害。

      另一方面,它几乎不会导致性能损失,因此删除只是为了“减少杂质”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-11-02
        • 1970-01-01
        • 1970-01-01
        • 2018-06-16
        • 1970-01-01
        • 1970-01-01
        • 2018-07-09
        • 2012-08-03
        相关资源
        最近更新 更多