为啥 Servlet 不是线程安全的? [复制]

Posted

技术标签:

【中文标题】为啥 Servlet 不是线程安全的? [复制]【英文标题】:Why Servlets are not thread Safe? [duplicate]为什么 Servlet 不是线程安全的? [复制] 【发布时间】:2012-03-22 06:53:22 【问题描述】:

我需要知道为什么 servlet 不是线程安全的? Struts 2.0 框架控制器 servlet 是线程安全的原因是什么?

【问题讨论】:

谁告诉你 servlet 不是线程安全的? @bmargulies 当然不会称它们为“线程安全的”,尽管我要警告说这完全取决于实现。传统观点称它们不是线程安全的。 相关:***.com/questions/3106452/… 欢迎来到 Stack Overflow。请阅读How to Ask、What have you tried?和How To s The Smart Way。 【参考方案1】:

我需要知道为什么 servlet 不是线程安全的?

Servlet 实例本质上不是线程安全的,因为 Java 编程语言通常具有多线程特性。 Java 虚拟机支持多线程执行相同的代码。这对于具有多个处理器的机器来说是一个巨大的性能优势。这也允许多个并发用户执行相同的代码,而不会相互阻塞。

想象一个有 4 个处理器的服务器,其中一个普通的 servlet 每秒可以处理 1000 个请求。如果该 servlet 是线程安全的,那么 Web 应用程序的行为就好像它运行在具有 1 个处理器的服务器上,其中 servlet 每秒只能处理 250 个请求(好吧,这不是完全那样,但是你明白了)。

如果您在使用 servlet 时遇到线程安全问题,那是 您的 错,而不是 Java 或 Servlet 的错。您需要修复 servlet 代码,使请求或会话范围的数据从不分配为 servlet 的实例变量。如需深入解释,另请参阅How do servlets work? Instantiation, sessions, shared variables and multithreading。

Struts 2.0 框架控制器 servlet 是线程安全的原因是什么?

它不是线程安全的。您将 Struts 调度程序 servlet 过滤器与 Struts 操作混淆了。每个请求都会重新创建 struts 操作。因此,每个请求都有自己的请求范围的 Struts 操作实例。 Struts 调度程序 servlet 过滤器不会将它们存储为它自己的实例变量。相反,它将其存储为HttpServletRequest 的一个属性。

【讨论】:

S2 实际上使用过滤器,而不是 servlet,这与 JEE 准则相反:/【参考方案2】:

Servlet 是普通的 java 类,因此不是线程安全的。

但是,如果您没有实例变量,Java 类是线程安全的。只有实例变量需要同步。 (实例变量是在类中声明的变量,而不是在其方法中。

方法中声明的变量是线程安全的,因为每个线程都创建自己的程序堆栈,并且函数变量在堆栈中分配。这意味着方法中的变量是为每个线程创建的,因此没有任何关联的线程同步问题。

方法变量是线程安全的,类变量不是。

【讨论】:

不太确定 只有实例变量需要同步。静态变量也需要同步,它们不是实例变量。 这是错误的,需要根据@ParamvirSinghKarwal 的评论进行更正。在类级别(不是方法级别)声明的 Java 变量分为两类:静态变量(也称为类变量)和实例变量(属于对象的变量)。说:“只有实例变量需要同步”是令人困惑的。当您的意思是“只有在类级别声明的变量(静态和实例变量)需要同步时。” - 阅读完整答案后,您的意图才会变得清晰。【参考方案3】:

每个 servlet 映射都有一个 servlet 实例;所有实例属性在所有请求之间共享。访问这些属性必须考虑到这一点。

Struts 2 动作(不是“控制器 servlet”,它们既不是 servlet 也不是控制器)是按请求实例化的。动作属性只能由单个请求的线程访问。

【讨论】:

【参考方案4】:

Servlet 通常是多线程的。

Servlet 容器通常通过为每个请求创建一个新的 Java 线程来管理并发请求。新线程被赋予对所请求 servlet 的对象引用,该 servlet 通过同一线程发出响应。这就是为什么在编写 servlet 时设计并发性很重要的原因,因为多个请求可能由同一个 servlet 实例处理。

servlet 容器处理 servlet 请求的方式取决于实现;他们可能使用单个 servlet,也可能使用 servlet pooling,这取决于供应商的系统架构。

Struts 2 Action 对象为每个请求实例化,因此不存在线程安全问题。

【讨论】:

【参考方案5】:

Servlet 不是线程安全的,但我们可以通过将 servlet 类实现为 SingleThreadModel 使其成为线程安全的 就像下面给出的类定义一样,但性能问题仍然存在,所以更好的选择是使用同步部分

public class SurveyServlet extends HttpServlet
                           implements SingleThreadModel

servlet code here..
...

【讨论】:

【参考方案6】:

Servlet 本身不是线程安全的。您可以通过使服务方法同步来使其成为线程安全的。 您需要实现 SingleThreadInterface 以使其成为线程安全的。

【讨论】:

如果 servlet 不是线程安全的,那么所有的 Java web 应用程序如何才能完美地工作,即使没有让它们实现 SingleThreadInterface?如果您错误地实现它们,它们就不是线程安全的。如果你这样做,它们就是线程安全的。

以上是关于为啥 Servlet 不是线程安全的? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Java 的 SimpleDateFormat 不是线程安全的? [复制]

为啥 java servlet 不是过滤器? [复制]

Servlet不是线程安全的。

servlet不是线程安全的

Swing:不使用 EDT 创建 GUI 是不是安全? [复制]

Servlet是线程安全吗?