zoukankan      html  css  js  c++  java
  • struts2的action是多例,servlet是单例

    援引博客园的文章:http://www.cnblogs.com/wangyayun/p/3804574.html


    struts2中action是多例的,即一个session产生一个action
    如果是单例的话,若出现两个用户都修改一个对象的属性值,则会因为用户修改时间不同,两个用户访问得到的


    属性不一样,操作得出的结果不一样.
    举个例子:有一块布长度300cm,能做一件上衣(用掉100cm)和一件裤子(用掉200cm);甲和乙同时访问得到的


    长度都是300cm,
    甲想做上衣和裤子,他先截取100cm去做上衣,等上衣做完再去做裤子,而乙这时正好也拿100cm去做上衣,那


    好,等甲做完上衣再做裤子的时候发现剩下的布(100cm)已经不够做裤子了.....这就是影响系统的性能,解决


    的办法就是给甲和乙一人一块300cm的布,就不会出现布被别人偷用的事情,也是就单实例和多实例的区别
    如果设置成单例,那么多个线程会共享一个ActionContext和ValueStack,这样并发访问的时候就会出现问


    题了
    struts 2的Action是多实例的并非单例,也就是每次请求产生一个Action的对象。原因是:struts 2的Action


    中包含数据,例如你在页面填写的数据就会包含在Action的成员变量里面。如果Action是单实例的话,这些


    数据在多线程的环境下就会相互影响,例如造成别人填写的数据被你看到了。所以Struts2的Action是多例


    模式的。
    问题出现了,可以让struts2的action变成单例模式么?我在使用spring来生成action的时候,发现生成的


    action居然全是单例的。这不是让我的程序默认就跑出bug来么?上个用户提交的信息,如果下个用户没填


    ,居然跑到上个用户输入的信息去了。
    背景:
    1) Struts2会对每一个请求,产生一个Action的实例来处理.
    2) Spring的Ioc容器管理的bean默认是单实例的.
    首先从数据安全性的问题上考虑,我们的Action应该保证是多例的,这样才不会出现数据问题。但是如果有


    的action比如只有admin才能操作,或者某些action,全站公用一个来提高性能,这样的话,就可以使用单


    例模式。
    不过幸好,Spring的bean可以针对每一个设置它的scope,所以,上面的问题就不是问题了。如果用单例,


    就在spring的action bean配置的时候设置scope="prototype".好吧,问题到此结束。


    而servlet采用单实例多线程模式开发,减少产生servlet实例的开销。


    servlet容器维护一个线程池,里面放着工作者线程来相应请求,同时还有一个调度线程来管理工作者线程。当容器收到一个servlet请求,调度线程就从线程池中取出一个工作者线程,该工作者线程将处理这个请求,做法是执行servlet的service方法;当这个线程执行时,收到另一个请求,调度线程就在线程池中取出另一个工作者线程来响应新的请求。容器不关心请求是否访问的是同一个servlet,当多个请求同时访问同一个servlet时,这个servlet的service方法将在多线程中并发执行。并发执行必然会出现同步问题,也就是线程的安全问题,下面是网上找到的原本版本。绕来绕去,总也绕不开几门基础课,终于明白为什么考研要考数据结构,操作系统,组成原理和网络原理了,这一个线程安全问题就涉及到数据结构和操作系统,数据结构帮助选择线程安全的数据类型,操作系统帮助找到线程安全的操作方法。


    一. Servlet容器如何同时来处理多个请求 
         工作者线程Work Thread:执行代码的一组线程 
         调度线程Dispatcher Thread:每个线程都具有分配给它的线程优先级,线程是根据优先级调度执行的 
         Servlet采用多线程来处理多个请求同时访问。servlet依赖于一个线程池来服务请求。线程池实际上是一系列的工作者线程集合。Servlet使用一个调度线程来管理工作者线程. 
         当容器收到一个Servlet请求,调度线程从线程池中选出一个工作者线程,将请求传递给该工作者线程,然后由该线程来执行Servlet的service方法。当这个线程正在执行的时候,容器收到另外一个请求,调度线程同样从线程池中选出另一个工作者线程来服务新的请求,容器并不关心这个请求是否访问的是同一个Servlet.当容器同时收到对同一个Servlet的多个请求的时候,那么这个Servlet的service()方法将在多线程中并发执行。 
          Servlet容器默认采用单实例多线程的方式来处理请求,这样减少产生Servlet实例的开销,提升了对请求的响应时间,对于Tomcat可以在server.xml中通过<Connector>元素设置线程池中线程的数目。 
         就实现来说: 
          调度者线程类所担负的责任是线程的调度,只需要利用自己的属性完成自己的责任。所以该类是承担了责任的,并且该类的责任又集中到唯一的单体对象中。 
    而其他对象又依赖于该特定对象所承担的责任,我们就需要得到该特定对象。那该类就是一个单例模式的实现了。 
        
    二 如何开发线程安全的Servlet 
        1,变量的线程安全:这里的变量指字段和共享数据(如表单参数值)。


          a,将 参数变量本地化。多线程并不共享局部变量.所以我们要尽可能的在servlet中使用局部变量。 
          例如:String user = ""; 
             user = request.getParameter("user");


          b,使用同步块Synchronized,防止可能异步调用的代码块。这意味着线程需要排队处理。 
    在使用同步块的时候要尽可能的缩小同步代码的范围,不要直接在sevice方法和响应方法上使用同步,这样会严重影响性能。


       2,属性的线程安全:ServletContext,HttpSession,ServletRequest对象中属性 
         ServletContext:(线程是不安全的) 
        ServletContext是可以多线程同时读/写属性的,线程是不安全的。要对属性的读写进行同步处理或者进行深度Clone()。 
         所以在Servlet上下文中尽可能少量保存会被修改(写)的数据,可以采取其他方式在多个Servlet中共享,比方我们可以使用单例模式来处理共享数据。 
         HttpSession:(线程是不安全的) 
         HttpSession对象在用户会话期间存在,只能在处理属于同一个Session的请求的线程中被访问,因此Session对象的属性访问理论上是线程安全的。 
         当用户打开多个同属于一个进程的浏览器窗口,在这些窗口的访问属于同一个Session,会出现多次请求,需要多个工作线程来处理请求,可能造成同时多线程读写属性。 
         这时我们需要对属性的读写进行同步处理:使用同步块Synchronized和使用读/写器来解决。


         ServletRequest:(线程是安全的) 
         对于每一个请求,由一个工作线程来执行,都会创建有一个新的ServletRequest对象,所以ServletRequest对象只能在一个线程中被访问。ServletRequest是线程安全的。 
        注意:ServletRequest对象在service方法的范围内是有效的,不要试图在service方法结束后仍然保存请求对象的引用。


    3,使用同步的集合类: 
        使用Vector代替ArrayList,使用Hashtable代替HashMap。


    4,不要在Servlet中创建自己的线程来完成某个功能。 
        Servlet本身就是多线程的,在Servlet中再创建线程,将导致执行情况复杂化,出现多线程安全问题。


    5,在多个servlet中对外部对象(比方文件)进行修改操作一定要加锁,做到互斥的访问。 
       
    6,javax.servlet.SingleThreadModel接口是一个标识接口,如果一个Servlet实现了这个接口,那Servlet容器将保证在一个时刻仅有一个线程可以在给定的servlet实例的service方法中执行。将其他所有请求进行排队。 
       服务器可以使用多个实例来处理请求,代替单个实例的请求排队带来的效益问题。服务器创建一个Servlet类的多个Servlet实例组成的实例池,对于每个请求分配Servlet实例进行响应处理,之后放回到实例池中等待下此请求。这样就造成并发访问的问题。 
    此时,局部变量(字段)也是安全的,但对于全局变量和共享数据是不安全的,需要进行同步处理。而对于这样多实例的情况SingleThreadModel接口并不能解决并发访问问题。


    SingleThreadModel接口在servlet规范中已经被废弃了。

    学习、成长
  • 相关阅读:
    hdu6229 Wandering Robots 2017沈阳区域赛M题 思维加map
    hdu6223 Infinite Fraction Path 2017沈阳区域赛G题 bfs加剪枝(好题)
    hdu6438 Buy and Resell 买卖物品 ccpc网络赛 贪心
    hdu6441 Find Integer 求勾股数 费马大定理
    bzoj 1176 Mokia
    luogu 3415 祭坛
    bzoj 1010 玩具装箱
    bzoj 3312 No Change
    luogu 3383【模板】线性筛素数
    bzoj 1067 降雨量
  • 原文地址:https://www.cnblogs.com/yarcl/p/11046793.html
Copyright © 2011-2022 走看看