Servlet生命周期与线程安全
2018-06-18 03:23:49来源:未知 阅读 ()
上一篇介绍了Servlet初始化,以及如何处理HTTP请求,实际上在这两个过程中,都伴随着Servlet的生命周期,都是Servlet生命周期的一部分。同时,由于Tomcat容器默认是采用单实例多线程的方式处理多个请求,这一特性就导致了线程安全问题的存在。因此,本篇主要讲述Servlet生命周期与线程安全问题。
1、Servlet生命周期
Servlet是运行在容器当中的,所以其生命周期也由容器控制,最常用的容器就是Tomcat,笔者经历过的所有项目也都是以Tomcat作为Servlet的容器。经过前面几篇介绍,相信大家对Servlet的生命周期有了一定的了解。Servlet的生命周期其实是通过javax.servlet.Servlet接口中的init()、service()、destroy()等方法表示的,主要有四个阶段组成:加载并实例化、初始化(init())、处理请求(service())、销毁(destroy())。下面分别介绍这四个阶段。
加载并实例化
Tomcat容器负责Servlet的加载并实例化,其实例化分两种情况:当web.xml文件里配置了<load-on-startup>标签并且里面的数字>=0时,容器启动时即加载Servlet类并创建类的实例;如果未配置<load-on-startup>标签或数字<0时,容器启动时不会加载Servlet类,当然也就不会创建类的实例。这时,当用户首次访问Servlet类时会加载并实例化。无论采用哪种方式实例化,都只会创建一个类的实例,无论多少用户访问Servlet,都共用这一个实例。
初始化(init())
在Servlet类实例化之后,容器将调用init()方法,传递ServletConfig接口的对象,进行初始化。在init()方法中,可以通过getServletConfig()方法获取ServletConfig对象,然后通过此对象的getInitParameter()等方法获取web.xml文件中<init-param>标签里面的配置信息,并对配置信息进行解析,或者执行任何其他一次性活动。在Servlet的整个生命周期中,init()方法只会被执行一次。
处理请求(service())
在Servlet初始化完成之后,容器就准备接收并处理客户的请求了。处理请求时,容器会调用Servlet的service(HttpServletRequest req, HttpServletResponse resp)方法,这个方法会判断用户发送的请求类型,是“POST”请求还是“GET”请求或是其他请求,然后根据请求类型执行相应的doPost()方法、doGet()方法或其他方法。Tomcat容器会将用户请求的数据封装到HttpServletRequest对象中,服务器处理完用户请求之后,将结果信息返回到HttpServletResponse对象中,最终这两个对象作为参数传递到doPost()、doGet()或其他方法中,将结果信息返回到页面显示。当多个客户的请求到来时,服务器会创建多个线程,每个客户请求对应一个线程,每个请求的service()方法都能运行在自己独立的线程中。
销毁(destroy())
当Tomcat容器关闭时或由于其他原因导致Servlet需要关闭或卸载时,容器会调用该对象的destroy()方法,以便让Servlet对象可以释放它所使用的资源,该方法同样只会执行一次。在容器调用destroy()方法前,如果还有其他的线程正在service()方法中执行,容器会等待这些线程执行完毕或者等待服务器设定的超时值到达。一旦Servlet对象的destroy()方法被调用,容器会释放这个Servlet对象,在随后的时间内,该对象会被java的垃圾收集器所回收。这四个阶段共同组成了Servlet的生命周期。
2、Servlet线程安全
通过上面的Servlet生命周期可以看出,在Tomcat容器加载并实例化Servlet之后,会创建一个实例,并且这个实例是唯一的,无论多少用户访问Servlet,都共用这一个实例。而每次用户访问Servlet时,服务器都会为每个用户创建一个独立的线程,每个线程都有它自己的堆栈空间。所以说是单实例多线程,这种默认以多线程方式执行的设计可大大降低对系统的资源需求,提高系统的并发量及响应时间,但也同时引发了Servlet的线程安全问题。
对于Servlet中的局部变量,多线程下每个线程对局部变量都会有自己的一份copy,存在自己的堆栈空间中,这样对局部变量的修改只会影响到自己的copy而不会对别的线程产生影响,所以这是线程安全的;对于Servlet中的实例(全局)变量,多线程下所有线程共享实例变量,这一共享就可能导致多个线程之间互相影响,从而引发线程的不安全。
知道了引发线程不安全问题的原因,那么该如何预防这一情况发生呢?
不使用实例变量
既然实例变量能引发线程安全问题,那么只要在Servlet类的任何方法里面都不使用实例变量,该Servlet就是线程安全的。事实上,线程安全问题大部分是由实例变量造成的,在Servlet中避免使用实例变量是保证Servlet线程安全的最佳选择。
使用synchronized
synchronized关键字能保证一次只有一个线程可以访问被保护的区段,所以理论上可以通过同步块操作来保证Servlet的线程安全。但因为其“一次只有一个线程可以访问”的特性,导致当大量用户访问同一资源时,只能排队访问,大量用户处于阻塞状态,这就大大降低了其用户的吞吐量,从而使系统的效率和性能大大降低,不推荐使用此方法。
其他方式
Java的有些集合类也会引发线程安全问题,应避免使用。比如用Vector代替ArrayList,用Hashtable代替HashMap等。另外,不要在Servlet中创建其他线程来完成某个功能,因为Servlet本身就是多线程的,再在Servlet中创建线程,更容易引发线程安全问题。
转载请注明出处 http://www.cnblogs.com/Y-oung/p/8433426.html
工作、学习、交流或有任何疑问,请联系邮箱:yy1340128046@163.com 微信:yy1340128046
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Invalid [xxx] in servlet mapping 、 <url-pattern& 2020-06-07
- 是时候了解下软件开发的生命周期了! 2020-06-06
- Maven+JSP+Servlet+C3P0+Mysql实现的音乐库管理系统 2020-05-22
- JSP+Servlet+JDBC+mysql实现的学生成绩管理系统 2020-05-17
- 别找了,回答Spring中Bean的生命周期,这里帮你总结好了 2020-05-12
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash