在struts应用的生命周期中,只会为每个action类创建一个实例,所有的客户请求共享这个实例。因此,必需保证在多线程环境中,action也能正常工作。保证线程安全的重要元素是在action类中仅仅使用局部变量,谨慎地使用实例变量。如果在action的execute()方法中定义了局部变量,对于每个调用execute()方法的线程,java虚拟机会在每个线程的堆栈中创建局部变量,因此每个线程拥有独立的局部变量,不会被其他线程共享。当线程执行完execute()方法时,它的局部变量就会被销毁。如果在action类中定义了实例变量,那么在action实例的整个生命周期中,这个实例变量被所有的请求线程共享。因此不能在action类中定义代表特定客户状态的实例变量。在action类中定义的实例变量代表了可以被所有请求线程访问的共享资源。为了避免共享资源的竞争,在必要的情况下,需要采用java同步机制对访问共享资源的代码块进行同步。
public class XXXAction extends BaseAction {
  protected String yyyy = null;
  ...
}这个变量yyyy才叫Action的实例变量
/*特别是execute方法中定义代表特定客户状态的实例变量*/,这句话不知道出自何处,感觉描述有问题

解决方案 »

  1.   

    再问您你一个问题,Servlet中的HttpSession是否是线程安全的,(我觉得应该是的)
    我听人说过,一个WEB应用中,只能有一个sesion(不是hibernate中的session)实例,甚至在多台服务器器的情况下,也只有一个session,我不知道这中说法是否正确。就我的理解,竟然所有用户可以共用一个检查用户登录信息是否正确的Action实例,为什么所有用户就不能共用一个session实例呢?但是好多书又说,容器会为每个用户创建一个session实例(会话),用于跟踪用户,我就很纳闷,那样的话,系统的开销会是多么的大,服务器会受得了,比如我们的CSDN,注册用户因该上了百万吧,用户同时在线,为每一个用户创建一个SESSION实例,那样
    要耗多少资源啊,说了这么多,我就是想知道session是否是线程安全的,一个web应用(可能我说得不是很清楚,比如有50万用户登录CSDN)到底容器是创建一个sessin实例让用户存放东西呢,还是为每一个用户创建一个SESSION实例??
      

  2.   

    毫无疑问,每个用户都有自己的session
    ------------------------------------------------
     session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。  当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为session id,如果已包含一个session id则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。  保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID,而。比如weblogic对于web应用程序生成的cookie,JSESSIONID=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764,它的名字就是JSESSIONID。  由于cookie可以被人为的禁止,必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面,附加方式也有两种,一种是作为URL路径的附加信息,表现形式为http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764另一种是作为查询字符串附加在URL后面,表现形式为http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
    这两种方式对于用户来说是没有区别的,只是服务器在解析的时候处理的方式不同,采用第一种方式也有利于把session id的信息和正常程序参数区分开来。  为了在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。  另一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如下面的表单  在被传递给客户端之前将被改写成 
     
      这种技术现在已较少应用,笔者接触过的很古老的iPlanet6(SunONE应用服务器的前身)就使用了这种技术。实际上这种技术可以简单的用对action应用URL重写来代替。  在谈论session机制的时候,常常听到这样一种误解“只要关闭浏览器,session就消失了”。其实可以想象一下会员卡的例子,除非顾客主动对店家提出销卡,否则店家绝对不会轻易删除顾客的资料。对session来说也是一样的,除非程序通知服务器删除一个session,否则服务器会一直保留,程序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会主动在关闭之前通知服务器它将要关闭,因此服务器根本不会有机会知道浏览器已经关闭,之所以会有这种错觉,是大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个session id就消失了,再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的HTTP请求头,把原来的session id发送给服务器,则再次打开浏览器仍然能够找到原来的session。  恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为seesion设置了一个失效时间,当距离客户端上一次使用session的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。
      

  3.   

    Action可以看作一个处理用户请求的处理器,它从actionform中获取输入数据,它本身可以无状态的。单实例或多实例没关系。(可能多实例消耗内存资源)
    session不同,他本身就是用来保持用户状态的,当然不能用单实例。
      

  4.   

    struts中的实例变量是不安全的
    public class XXXAction extends BaseAction {
    protected int i = 1;
    ...
    }
    你可以试试上面的代码,然后每个execute中都加1一次,你可以发现无论什么用户登录,每次执行action都在原有的基础上加1了,说明他是非线程安全的。整个的action只是创建一个实例,这个和webwork不同,webwork的每次请求都创建一个action实例。