zoukankan      html  css  js  c++  java
  • 对于多线程下Servlet以及Session的一些理解

    今天,小伙伴突然问到了Servlet是不是线程安全的问题。脑子当时一卡壳,只想到了单实例多线程。这里做一些总结。

    Servlet体系是建立在Java多线程的基础之上的,它的生命周期是由Tomcat来维护的。当客户端第一次请求Servlet的时候,tomcat会根据web.xml配置文件实例化servlet,当又有一个客户端访问该servlet的时候,不会再实例化该servlet,也就是多个线程在使用这个实例。

    Servlet线程池

                     serlvet采用多线程来处理多个请求同时访问,Tomcat容器维护了一个线程池来服务请求。

                 线程池实际上是等待执行代码的一组线程叫做工作组线程(Worker Thread),Tomcat容器使用一个

                 调度线程来管理工作组线程(Dispatcher Thead)。

                  

                           当容器收到一个Servlet请求,Dispatcher线程从线程池中选出一个工作组线程,将请求传递

                   给该线程,然后由该线程来执行Servlet的service方法。

                           当这个线程正在执行的时候,容器收到另一个请求,调度者线程将从线程池中选出另外一个

                   工作组线程来服务则个新的请求,容器并不关心这个请求是否访问的是同一个Servlet还是另一个

                   Servlet。当容器收到对同一个Servlet的多个请求的时候,那这个servlet的service方法将在多线程

                   中并发的执行。

               Servlet线程安全问题

                          多线程和单线程Servlet具体区别:多线程下每个线程对局部变量都会有自己的一份copy,这

                   样对局部变量的修改只会影响到自己的copy而不会对别的线程产生影响,线程安全的。但是对于

                   实例变量来说,由于servlet在Tomcat中是以单例模式存在的,所有的线程共享实例变量。多个线程

                   对共享资源的访问就造成了线程不安全问题。

    那么如何使Servlet线程安全呢?

    设计线程安全的Servlet

                      针对上述的情况如何设计线程安全的Servlet呢?我们知道的是多线程是不共享局部变量的

                  servlet线程不安全也是针对于共享资源的访问才产生的。 因此这里就有一种方式了。

                 变量的线程安全

                       这里的变量变量指的是字段和共享数据,主要是表单的参数值。基于多线程不共享局部变量的

                  特点我们可以将这类变量参数本地化。例如对于上面的一个实例我们可以这样设计 

     1 protected void doPost(HttpServletRequest request,  
     2             HttpServletResponse response) throws ServletException, IOException {  
     3         String message;  
     4         message = request.getParameter("message");  
     5         PrintWriter printWriter = response.getWriter();  
     6         try {  
     7             Thread.sleep(5000);  
     8         } catch (InterruptedException e) {  
     9             // TODO Auto-generated catch block  
    10             e.printStackTrace();  
    11         }  
    12         printWriter.write(message);  
    13     }  

                   属性的线程安全

                          ServletContext:它是线程不安全的,多线程下可以同时进行读写,因此我们要对其读写操作进行

                     同步或者深度的clone。

                          HttpSession:同样是线程不安全的,和ServletContext的操作一样。

                          ServletRequest:它是线程安全的,对于每一个请求由一个工作线程来执行,都会创建一个

                     ServletRequest对象,所以ServletResquest只能在一个线程中被访问,而且他只在service()方法内是

                     有效的。

                    同步的集合类

                         在使用java中的集合API进行处理的时候,选择同步的集合。

                    外部对象互斥

                         在多个Servlet中对某个外部对象(例如文件)的修改是务必加锁,互斥访问。不过这里需要注意的是

                     使用Synchronized的时候这意味着线程需要排队等待处理,因此在使用同步块的时候要尽量的缩小同

                     步块的代码范围。不要直接在方法上用同步,这样会严重影响性能。

                         值得一提的是最好别再serlvet中创建自己的线程来完成某个功能,这会是情况更加复杂。

                 Single ThreadMode接口

                          这也是解决servlet线程安全问题的一个方法,Single ThreadMode是一个标识接口,如果一个Servlet

                      实现了该接口,那么Tomcat将保证在一个时刻仅有一个线程可以在给定的Serlvet实例的service方法中

                      执行。其他所有请求进行排队。(针对单个实例)

                           可以看出的是这种方式虽然可以解决线程安全问题,可以效率太过低下。

                           其再Servlet的规范中已经被废弃了。

                总结

                         Servlet的线程安全问题只有在大量的并发访问时才会显现出来,并且很难发现,因此在编写Servlet程序

                     时要特别注意。线程安全问题主要是由实例变量造成的,因此在Servlet中应避免使用实例变量。如果应用程

                     序设计无法避免使用实例变量,那么使用同步来保护要使用的实例变量,但为保证系统的最佳性能,应该

                     同步可用性最小的代码路径。

    下面来说第二部分: HttpSession

    http://blog.csdn.net/haitao111313/article/details/7735620

  • 相关阅读:
    HDOJ 4747 Mex
    HDU 1203 I NEED A OFFER!
    HDU 2616 Kill the monster
    HDU 3496 Watch The Movie
    Codeforces 347A A. Difference Row
    Codeforces 347B B. Fixed Points
    Codeforces 372B B. Hungry Sequence
    HDU 1476 Sudoku Killer
    HDU 1987 How many ways
    HDU 2564 词组缩写
  • 原文地址:https://www.cnblogs.com/protected/p/6762185.html
Copyright © 2011-2022 走看看