Servlet —— 避免Servlet的并发同步问题

时间:2023-03-08 19:04:50

Servlet的生命周期是由Servlet容器来负责的。

Servlet容器通常采用单实例多线程的方式,减少Servlet创建实例的开销,提高效率。

Servlet —— 避免Servlet的并发同步问题

当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类(如果设置了on-start-up,启动时就会实例化)。当又有新的客户端请求该servlet时,一般不会再次实例化该servlet类,也就是有多个线程在同时使用这个servlet实例。

因此,当有两个或多个线程同时访问一个Servlet时,可能会发生多个线程同时访问同一资源的问题。

Servlet的线程安全问题主要是由于Servlet实例变量使用不当导致的,例如:

  1. public MyServlet extends HttpServlet{
  2. 实例变量 output;
  3. public void service(ServletRequest request, ServletResponse){
  4. 局部变量 username;
  5. ... ...
  6. 对实例变量output的操作;   // 可能导致同步问题
  7. ... ...
  8. 对局部变量username的操作; // 不会导致同步问题
  9. ... ...
  10. }
  11. }

Servlet实例的JMM(Java Memory Model)模型:

Servlet —— 避免Servlet的并发同步问题

根据JMM,系统存在一个主内存,Java中所有实例变量都存储在主存中,对于所有线程都是共享的。每条线程都有自己的工作内存,工作内存由缓存和堆栈组成:缓存中保存的主存中变量的拷贝,缓存可能并不总和主存同步,也就是缓存中变量的修改可能没有立刻写到主存中;堆栈中保存的是线程的局部变量,线程之间无法相互直接访问堆栈中的变量。

避免同步问题

  • 避免使用实例变量(主要使用方法)
  • 同步代码块synchronized
    • 使用SingleThreadModel接口(废弃)