Servlet 是单例还是多例?

面试中经常会被问到:Servlet 是单例还是多例,这是一个很基础的问题,主要考察面试者的基础是否扎实。还可以关联出一串更深层的问题来考察面试者的知识深度。

问:Servlet是单例还是多例?
答:单例
问:单例情况下在多个请求时是怎么处理的?
答:多线程,为每个请求分配一条线程
问:单例在并发情况下线程是否安全?
答:不安全
问:有没有办法解决?
答:有。。。。如果回答可以使用 ThreadLocal来隔离每个请求的线程是最好的。接着更深的坑
问:ThreadLocal 的原理是什么?怎么实现的?
答:。。。。答不上来 OR 回答上来了。后面正等着呢
问:使用ThreadLocal与同步代码块,那个优劣?
问:多线程。。。。并发。。。。。
答:。。。。死穴。。。。OVER

Servlet是单例还是多例

  1. 查看 Servlet 定义

     For a servlet not hosted in a distributed environment (the default), 
     the servlet container must use only one instance per servlet declaration. 
     如果 servlet 不是在分布式环境下(默认),servlet 容器必须使一个 servlet 实例对应一个 servlet 声明。 
     
     However, for a servlet implementing the SingleThreadModel(Deprecated) interface,
     the servlet container may instantiate multiple instances to handle a heavy 
     request load and serialize requests to a particular instance. 
     然而,实现了 SingleThreadModel 接口的 Servlet,可以有多个实例。以处理繁重的请求,
     并且序列化 request 到特定的 servlet 实例。 
     
     public interface SingleThreadModel 
     Ensures that servlets handle only one request at a time. 
    

  因SingleThreadModel已经声明为废弃,官方不建议使用,所以此种情况可以不予考虑。

  Servlet 在多数情况下只有一个实例。但它并不是单例设计模式,即不是真正的单例。
查看 Tomcat 源码StandardWrapper 分析,当Web服务启动时(或客户端发送请求到服务器时),Servlet 就被加载并实例化了一次。

  Servlet 是单例还是双例,与web.xml文件里声明的 Servlet 次数有关。如果在web.xml文件同一个 Servlet 映射了多个 <url-pattern>,也会生成多例。

参考:Servlet到底是单例还是多例你了解吗?

Servlet线程安全问题

Servlet 默认是单实例多线程来响应多个请求,这样就存在线程安全问题。如果有多个客户端同时请求JSP文件,则服务端会创建多个线程,每个请求对应一个线程。以下方法可解决线程安全问题:

  1. 使用同步块(或方法)来保护共享数据
     同步来保护要使用的共享的数据,也会使系统的性能大大下降。
     这是因为被同步的代码块在同一时刻只能有一个线程执行它,使得其同时处理客户请求的吞吐量降低,而且很多客户处于阻塞状态。
     另外为保证主存内容和线程的工作内存中的数据的一致性,要频繁地刷新缓存,这也会大大地影响系统的性能。
     所以在实际的开发中也应避免或最小化 Servlet 中的同步代码;

  2. 避免使用实例变量
     在 Serlet 中避免使用实例变量是保证Servlet线程安全的最佳选择。从Java 内存模型也可以知道,方法中的临时变量是在栈上分配空间,而且每个线程都有自己私有的栈空间,所以它们不会影响线程的安全。

  3. 可以使用 ThreadLocal来隔离线程,实现线程内部变量独占
    参考:Servlet线程安全问题——ThreadLocal模式

  4. 可以使用 Lock 机制来实现
    参考:JAVA多线程不安全问题解决方案
       servlet单实例多线程模式

作者

光星

发布于

2017-12-31

更新于

2022-06-17

许可协议

评论