【问题标题】:Singleton vs Single Thread单例与单线程
【发布时间】:2010-10-16 17:05:23
【问题描述】:

通常 Servlet 只启动一次,Web 容器简单地为每个用户请求生成一个新线程。假设我从头开始创建自己的 Web 容器,而不是线程,我只是将 Servlet 创建为 Singleton。我会在这里遗漏什么吗?我想,在这种情况下,单例一次只能服务一个用户请求,而不是多个。

【问题讨论】:

  • 您想要解决的目标/目的或问题是什么?

标签: servlets concurrency


【解决方案1】:

通常 Servlet 只启动一次,Web 容器简单地为每个用户请求生成一个新线程。

第一个陈述是正确的,但第二个实际上不是。通常,线程在应用程序启动期间创建一次,并保存在线程池中。当一个线程完成了它的请求-响应处理工作,它将被返回到池中。这也是为什么在 servlet 容器中使用 ThreadLocal 必须非常小心的原因。

假设我从头开始创建自己的 Web 容器,而不是线程,我只是将 Servlet 创建为 Singleton。我会在这里遗漏什么吗?

它们不一定需要遵循单例模式。只需在应用程序启动期间创建它们的一个实例,并在应用程序的整个生命周期中将它们保存在内存中,并让所有线程访问同一个实例。

我想,在这种情况下,单例一次只能服务一个用户请求,而不是多个。

这不是真的。只有在应用程序范围的锁上同步对单例方法的访问时才会发生这种情况。例如,在您的 servlet 方法中添加 synchronized 修饰符,或者在将请求委托给 servlet 的管理器方法中添加 synchronized(this)

【讨论】:

    【解决方案2】:

    JavaEE 曾经为此提供一种机制 - 一个名为 SingleThreadModel 的标记接口,您的 servlet 可以实现该接口:

    确保 servlet 一次只处理一个请求。这个接口没有方法。

    如果一个 servlet 实现了这个接口,就可以保证在 servlet 的 service 方法中不会有两个线程同时执行。 servlet 容器可以通过同步对 servlet 的单个实例的访问,或者通过维护一个 servlet 实例池并将每个新请求分派给一个空闲的 servlet 来保证这一点。

    请注意,SingleThreadModel 并不能解决所有线程安全问题。例如,会话属性和静态变量仍然可以被多个线程上的多个请求同时访问,即使使用 SingleThreadModel servlet 也是如此。建议开发人员采取其他方式来解决这些问题,而不是实现此接口,例如避免使用实例变量或同步访问这些资源的代码块。此接口在 Servlet API 版本 2.4 中已弃用。

    容器可以使用它为每个请求实例化一个新的 servlet,或者维护一个它们的池,如果它们愿意的话。

    由于上述原因,这在 Servlet 2.4 中已被弃用。这些相同的原因仍然适用于您的问题。

    【讨论】:

      【解决方案3】:

      基本上就是这样。

      我会质疑创建自己的容器的动机,因为有这么多可用于广泛的目的。

      【讨论】:

      • 好吧,我只是举个例子。当然不会真的重新发明轮子。
      猜你喜欢
      • 1970-01-01
      • 2013-06-02
      • 1970-01-01
      • 2012-08-28
      • 1970-01-01
      • 2010-10-03
      • 2011-06-02
      • 2010-11-16
      • 1970-01-01
      相关资源
      最近更新 更多