Servlet 是线程安全的吗?

概要

Servlet 默认是单例模式,在web 容器中只创建一个实例,所以多个线程同时访问servlet的时候,Servlet是线程不安全的。
那么 web 容器能为每个请求创建一个Servlet的实例吗?当然是可以的,只要Servlet实现SingleThreadModel接口,就可以了。

SingleThreadModel

该接口为每次请求创建一个servlet实例。此接口没有方法,跟Serializable接口一样只是一个标识接口。

注意,singlethreadmodel并不能解决所有的线程安全问题。例如,会话属性和静态变量仍然可以同时通过多线程的多个请求访问,即使用实现SingleThreadModel 接口的 servlet。建议开发人员采取其他方法来解决这些问题,而不是实现此接口,
例如避免使用实例变量或同步访问这些资源的代码块。
SingleThreadModel这个接口 Servlet API 2.4版本过时,不推荐大家使用了因为它存在性能问题,下面会介绍。

SingleThreadModel 使用示例

import javax.servlet.SingleThreadModel 
public class MyServlet extends HttpServlet implements SingleThreadModel {

只要Servlet实现 SingleThreadModel 接口就可以了。

Servlet 对象创建 源码分析

org.apache.catalina.core.StandardWrapper类是对应一个Servlet的容器,下面我们分析StandardWrapper是怎么创建Servlet实例的。

allocate() 创建Servlet 实例

首先判断当前servlet是不是 SingleThreadModel,如果不是,则使用双重检查的方式创建 instance 单例实例。 通过调用loadServlet方法进行创建 instance。

  • 只要Servlet不是SingleThreadModel,则创建Servlet的单例实例

如果第一次访问Servlet,则singleThreadModel属性默认是false,需要调用loadServlet方法加载Servlet后才能判断该Servlet是不是SingleThreadModel模式。

  1. 如果是SingleThreadModel模式并且是新创建的实例,则把当前instance添加到instancePool中,并nInstances++。
  2. 如果不是SingleThreadModel模式,则更新countAllocated+1,并且返回Servlet的instance实例

只有SingleThreadMode才能到synchronized块,因为,不是SingleThreadMode的已经执行return方法了。
判断当前Servlet创建的实例数量是否超过了maxInstances数量,默认maxInstances=20
如果超过当前则wait等待,否则,调用loadServlet()创建Servlet实例并添加到instancePool中。并更新nInstances数量。

  • 从这里可以看出每次都会调用loadServlet()方法来创建Servlet实例对象的。

SingleThreadMode 性能问题

从这里看出如果使用SingleThreadMode 模式,有两处性能问题

  1. 每个Servlet 创建多个对象实例
  2. 如果并发高,每个servlet同时只能支持20线程的并发访问。挂起超过20个的线程。

loadServlet() 方法

  1. 创建Servlet实例对象
  2. 判断该Servlet 是不是 SingleThreadMode
  3. 初始化Servlet

想了解更多精彩内容请关注我的公众号

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,923评论 18 139
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,366评论 11 349
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,765评论 18 399
  • 前两天,有个人问我“servlet是线程安全的吗?“,我却很难给出一个很具体清晰的回答,今天重新整理一下思路,也复...
    屎倒淋头还嚼便阅读 337评论 1 0
  • ''至於烈炭炙活鵝之掌,刀以取生雞之肝,皆君子所不為也。何也?物為人用,使之死可也,使之求死不得不可也!''
    NoBlackCoffee阅读 828评论 0 0