您的位置:首页 > Web前端 > JavaScript

Servlet、jsp的生命周期,线程安全,感悟

2011-12-16 11:06 417 查看
在学Servlet、JSP时候,对于servlet什么时候创建实例?什么时候调用init()方法,init()方法有什么作用?service()方法何时调用?如何处理请求?init()、jspInit()、service()、_jspService()、destroy()、jspDestroy()能不能覆盖?ServletContext作用域、HttpSession作用域、HttpServletRequest作用域线程安全吗?非线程安全又如何同步?


Servlet生命周期:1、容器找到*servlet.class文件,加载类文件Class.forName(),2、调用构造函数实例化,读取web.xml文件,对相关初始化参数<init-param></init-param><context-param></context-param>及各种生命周期事件监听器<listener></listener>进行加载创建键值对引用,3、容器创建ServletConfig对象、ServletContext对象,并分别取得之前创建的键值对引用,4、在调用servlet实例的init()方法,取得对ServletConfig的引用,最终完成初始化,形成一个真正的Servlet。


在调用完构造函数后,init()方法之前,servlet实例只是半个真正的Servlet只有用ServletConfig进行init()初始化以后菜式一个真正的Servlet,每个Servlet对应于一个ServletConfig,相当于配置参数之类的。用于配置Servlet。


初始化之后,对每一个请求,容器分别新建一个线程用service()进行处理,每个请求对应于一个线程(这很关键,涉及到线程安全) 。处理完之后,容器调用distory()方法销毁。


这三个方法都可以覆盖,init()用于初始化连接,destroy()用于释放资源,service()可以覆盖,也可以覆盖doGet(),doPost()等方法,用于处理请求。


对于JSP而言,生命周期如下:读取web.xml配置描述文件,等请求到来jsp转化为servlet文件,进行编译成class文件,加载类,构造函数实例化,调用jspInit()初始化。整个过程和servlet差不多,只不过在第一次的时候多了转化为servlet文件、编译成class文件两个步骤。


对应于每个请求也是新建一个线程用_jspService()方法进行那个处理。处理完之后有容器调用jspDestroy()销毁。


这三个方法只有jspInit(),jspDestroy()可以覆盖,在<%! %>中进行覆盖,_jspService()用于处理请求,不能覆盖,注意加了下划线_哦。


然后是作用域。


由于对每个请求容器都分配一个线程进行处理,这样就可能导致非线程安全问题。


1)对于ServletContext即上下文作用域,非线程安全。不同ServletConfig,ServletContext每个web应用对应一个ServletContext,而每个Servlet对应一个ServletConfig,因此ServletContext是对各个servlet共享的,因此对于不同客户不同请求是共享的,这样就会有线程安全问题。一个线程设置属性后,另一个线程并发也设置属性,等这个线程访问刚设置的属性就会出错。如同数据库中的并发控制,读到了脏数据。


解决:对上下文加锁,而不是对servlet加锁。对servlet加锁(另一个servlet还是能访问到)。


ServletContext ctx =  getServletContext(); 
        synchronized(ctx){
                ctx.setAttribute(str,object);//所有对于ServletContext的操作都在这里,进行加锁,这样会线程安全
         }



2)对于HttpSession会话作用域,非线程安全。由于一个客户可能同时进行多个请求,用于网速等原因,用户可能同时开多个窗口,进行并发访问service()方法,对于不同的请求,不同的线程,一个线程进行设置了,另一个线程进行修改了,这个线程在进行修改则会读到脏数据。


解决:对HttpSession进行加锁。

HttpSession session = request.getSession(); 
        synchronized( session  ){
                session  .setAttribute(str,object);//所有对于 session  的操作都在这里,进行加锁,这样会线程安全
        }



3)HttpServletRequest请求作用域是线程安全的。不同请求不同线程,这样是线程安全的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: