servlet线程安全问题

来源:互联网 发布:淘宝企业店铺注册资料 编辑:程序博客网 时间:2024/05/22 14:23

        前言

                在上一篇关于Serlvet框架和Servlet生命周期的学习中,我们已经知道了在多线程的情况下

            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中是以单例模式存在的,所有的线程共享实例变量。多个线程

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

                     对于单线程而言就不存在这方面的问题(static变量除外)

                     这里我们写一个实例来模拟一下:               

[java] view plaincopyprint?
  1. package com.kiritor;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.PrintWriter;  
  5.   
  6. import javax.servlet.ServletException;  
  7. import javax.servlet.http.HttpServlet;  
  8. import javax.servlet.http.HttpServletRequest;  
  9. import javax.servlet.http.HttpServletResponse;  
  10.   
  11. /** 
  12.  * Servlet implementation class ThreadServlet 
  13.  */  
  14. public class ThreadServlet extends HttpServlet {  
  15.     private static final long serialVersionUID = 1L;  
  16.     private String message;  
  17.   
  18.     /** 
  19.      * @see HttpServlet#HttpServlet() 
  20.      */  
  21.     public ThreadServlet() {  
  22.         super();  
  23.         // TODO Auto-generated constructor stub  
  24.     }  
  25.   
  26.     /** 
  27.      * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse 
  28.      *      response) 
  29.      */  
  30.     protected void doGet(HttpServletRequest request,  
  31.             HttpServletResponse response) throws ServletException, IOException {  
  32.         this.doPost(request, response);  
  33.     }  
  34.   
  35.     /** 
  36.      * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse 
  37.      *      response) 
  38.      */  
  39.     protected void doPost(HttpServletRequest request,  
  40.             HttpServletResponse response) throws ServletException, IOException {  
  41.         message = request.getParameter("message");  
  42.         PrintWriter printWriter = response.getWriter();  
  43.         try {  
  44.             Thread.sleep(5000);  
  45.         } catch (InterruptedException e) {  
  46.             // TODO Auto-generated catch block  
  47.             e.printStackTrace();  
  48.         }  
  49.         printWriter.write(message);  
  50.     }  
  51.   
  52. }  
           之后我们在打开两个浏览器:

                 http://localhost:8080/Servlet03/ThreadServlet?message=helloA

                 http://localhost:8080/Servlet03/ThreadServlet?message=helloB

               我们不断的尝试刷新浏览器,可以发现的是输出结果并不是我们想象的那么简单,而且错误的输出

            是具有偶然性的,这更增加了程序潜在的危险性。

               至于其实际的输出效果笔者就贴图了,读者可自行进行演示。

          设计线程安全的Servlet

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

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

             变量的线程安全

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

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

[java] view plaincopyprint?
  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中应避免使用实例变量。如果应用程

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

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

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 一年级的孩子不爱写字怎么办 一年级孩子不爱写作业怎么办 一年级的小孩不爱写字怎么办 小孩儿写字做作业磨蹭怎么办 孩子不学习成绩差不写作业怎么办 儿童4岁不会写字怎么办 小孩读中班还不会写字怎么办 幼儿园中班孩子不写字怎么办 小孩吃多了呕吐怎么办 一岁宝宝老便秘怎么办 4周岁半幼儿便秘怎么办 没胃口不能吃辣怎么办 九个月宝宝缺锌怎么办 宝宝4 5天不吃饭怎么办 16个月宝宝不肯吃饭怎么办 儿童不吃饭很瘦怎么办 小孩吃饭吃的少怎么办 宝宝突然晚上不睡觉怎么办 l岁宝宝吃多了怎么办 3个月婴儿厌食怎么办 11个月婴儿厌食怎么办 7个月的婴儿厌食怎么办 小孩记忆不好读书记不住怎么办 9岁儿童不爱睡觉怎么办 6岁儿童不爱吃饭怎么办 2岁半宝宝不吃饭怎么办 一年级的孩子不爱学习怎么办 小孩不爱写作业怎么办啊 孩子不爱看书怎么办如何教育 2岁宝宝不爱看书怎么办 儿媳妇比儿子年龄大我不喜欢怎么办 不喜欢儿子却生了儿子怎么办 静不下心来看书怎么办 孩子爱玩不爱学怎么办 孩子爱玩不爱学习怎么办 孩子爱玩手机不爱学习怎么办 照四维宝宝太活泼了怎么办 胎宝宝太活泼了怎么办 7个月宝宝太活泼怎么办 我是个初中生不想上学怎么办 3岁宝宝不肯说话怎么办