为什么Servlets不是线程安全的?

37

我需要知道为什么Servlets不是线程安全的?而在Struts 2.0框架中,控制器Servlet为什么是线程安全的?


谁告诉你Servlet不是线程安全的? - bmargulies
@bmargulies 我肯定不会称它们为“线程安全”,尽管我必须说明这完全取决于实现。传统智慧认为它们不是线程安全的。 - Dave Newton
相关链接:https://dev59.com/GnA75IYBdhLWcg3wy8Qi - BalusC
欢迎来到 Stack Overflow。请阅读 如何提问你尝试过什么?如何聪明地提问 - user647772
6个回答

51
我需要知道为什么Servlet不是线程安全的?
由于Java编程语言的多线程特性,Servlet实例本质上不是线程安全的。Java虚拟机支持多个线程执行相同的代码,这对于具有多个处理器的机器来说是一个巨大的性能优势。这也允许多个并发用户执行相同的代码而不会相互阻塞。
想象一台有4个处理器的服务器,其中一个普通的Servlet可以处理每秒1000个请求。如果该Servlet是线程安全的,那么Web应用程序就像在一台只有1个处理器的服务器上运行一样,其中Servlet只能处理每秒250个请求(好吧,它不完全是这样,但你明白了吧)。
如果在使用Servlet时遇到线程安全问题,那么这是你的问题,而不是Java或Servlet的问题。您需要修复Servlet代码,使请求或会话范围的数据永远不会被分配为Servlet的实例变量。有关详细说明,请参见Servlets如何工作?实例化,会话,共享变量和多线程
“那Struts 2.0框架控制器Servlet为什么是线程安全的?”它不是线程安全的。您将Struts分派程序Servlet过滤器与Struts操作混淆了。 Struts操作在每个请求上重新创建。因此,每个请求都有其自己的请求范围Struts操作实例。 Struts分派程序Servlet过滤器不将它们存储为自己的实例变量。相反,它将其存储为HttpServletRequest的属性。

3
S2实际上使用了一个过滤器,而不是Servlet,这与JEE指南相反 :/ - Dave Newton

22

Servlet是普通的Java类,因此它们不是线程安全的。

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

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

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


4
“只有实例变量需要同步”这句话我不太确定。静态变量也需要同步,而它们并非实例变量。 - Paramvir Singh Karwal
这是错误的,需要根据@ParamvirSinghKarwal的评论进行更正。在Java中,声明在类级别(而不是方法级别)的变量分为两类:静态变量(也称为类变量)和实例变量(属于对象的变量)。当您说:“只有实例变量需要同步”时,这很令人困惑,因为您的意思是“只有在类级别声明的变量(静态变量和实例变量)需要同步。”-只有在阅读完整个答案后,您的意图才变得清晰。 - Mindaugas Bernatavičius

11

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

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


2

Servlet通常是多线程的。

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

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

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


1

Servlet不是线程安全的,但我们可以通过将该servlet类实现为SingleThreadModel来使其成为线程安全的,如下所示的类定义,但性能问题仍然存在,因此更好的选择是使用同步部分。

public class SurveyServlet extends HttpServlet
                           implements SingleThreadModel
{
servlet code here..
...
}

0

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


如果一个Servlet不是线程安全的,那么所有的Java Web应用程序怎么能在没有实现SingleThreadInterface的情况下无缝运行呢?如果你实现不正确,它们就不是线程安全的。只有你让它们变得线程安全,它们才会是线程安全的。 - JB Nizet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接