概要

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

本人简书blog地址:http://www.jianshu.com/u/1f0067e24ff8    
点击这里快速进入简书

GIT地址:http://git.oschina.net/brucekankan/
点击这里快速进入GIT

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐