上一篇介绍了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

转载于:https://www.cnblogs.com/Y-oung/p/8433426.html

Servlet生命周期与线程安全相关推荐

  1. Servlet的生命周期和线程安全问题

    目录 Servlet简介 Servlet 架构图 Servlet 任务 Servlet的生命周期 init() 方法 service() 方法 doGet() 方法 doPost() 方法 destr ...

  2. Servlet生命周期与工作原理

    Servlet生命周期分为三个阶段: 1,初始化阶段  调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法 Servlet初始化阶段: 在 ...

  3. 【Servlet】Servlet生命周期

    Servlet生命周期是指Servlet实例从创建到响应客户请求,直至销毁的过程. Servlet程序本身不直接在Java虚拟机上运行,由Servlet容器负责管理其整个生命周期. Servlet生命 ...

  4. Web容器和Servlet生命周期

    为何需要Web容器 Web服务器本身主要用于支持http协议,包括监听和相应http请求.web服务器一般处理静态的请求,如文件系统中的静态文件.web容器则是为web相关的组件提供运行环境,可以从' ...

  5. 【JavaLearn】#(23)JSP相关语法、HTTP协议、Servlet介绍、Servlet生命周期、请求和响应、相对路径、转发和重定向

    1. JSP简单内容 1.1 JavaEE JavaEE 包含JSP JavaEE是一个开发分布式企业级应用的规范和标准.JavaEE包含之前学过的所有内容(JavaSE) 真正开发中,很少使用Jav ...

  6. 详解servlet生命周期

    详解servlet 生命周期(转载) Servlet 有良好的生存期的定义,包括如何加载.实例化.初始化.处理客户端请求以及如何被移除.这个生存期由 javax.Servlet.Servlet 接口的 ...

  7. Servlet生命周期(图解)

    1.Servlet生命周期其实很简单:只有一个主要状态--初始化.如果Servlet没有初始化,则要要么正在初始化(运行构造函数及init()方法).正在撤消(运行其destory()方法),要么就是 ...

  8. servlet生命周期(很有用)

    Servlet简介及其生命周期详解简介Servlet生命周期,即阐述Servlet从产生到毁灭的整个过程. 在Servlet产生到消亡的过程中,有三个生命周期函数,初始化方法init(),处理客户请求 ...

  9. 容器与Servlet生命周期

    1)容器大致功能有如下: 一.通信支持 无需自己建立监听端口.流.Socket等,容器知道与Web服务器的协议,所以不必担心自己的代码如何与服务器进行通信,交给容器就好 二.生命周期管理 容器可以自动 ...

  10. **servlet生命周期**

    Servlet 生命周期可被定义为从创建直到毁灭的整个过程.以下是 Servlet 遵循的过程: Servlet 通过调用 init () 方法进行初始化. Servlet 调用 service() ...

最新文章

  1. IOS时间传递机制简记
  2. [Hihocoder 1289] 403 Forbidden (微软2016校园招聘4月在线笔试)
  3. 最长公共子序列Java代码实现
  4. 剑指Offer #13 调整数组顺序使奇数位于偶数前面 | 图文详解
  5. 清华出版社送书 50 本,倒计时!
  6. 计算机本科毕业设计:毕业设计、论文要点及我们面对毕业答辩应持有的态度
  7. python如何截长图_使用python实现对元素的长截图功能
  8. 网页防篡改技术_阿里云云安全中心和web应用防火墙的网页防篡改功能有什么不同...
  9. Prometheus Alertmanager 报警模块
  10. decide your linux OS is GUI or not
  11. c c++ 宏定义中#, ##, #@的含义
  12. 交互原型案例Axure50套
  13. 移动端UML图应用之UML结构图——包图、部署图和组件图
  14. 202. 快乐数 (Python 实现)
  15. Android 网易云信直播
  16. 微信公众号创建菜单注意问题
  17. java我的世界溺尸为啥这么少,我的世界:溺尸刷新几率存在问题?溺尸刷怪塔为何得不到三叉戟?...
  18. 2022Java面试笔记(上)
  19. thunderbird 雷鸟中文版下载,安装
  20. 和平精英灵敏度分享码服务器没有响应,和平精英主播灵敏度

热门文章

  1. LINUX UBUNTU安装依赖库编译freeswitch
  2. 命令行编译并运行JAVA
  3. 开机启动实际上有两种情形
  4. 今天开始,吾使用手机上的五笔输入法
  5. html设置隐藏窗口,html – 在窗口大小调整时逐个隐藏菜单项
  6. 用于创建此对象的程序是excel_一起学Excel专业开发22:使用类模块创建对象1
  7. python中比较重要的几个函数_python几个重要的内置函数
  8. centos中多台主机免密登录_mac ssh 免用户名密码远程登录 linux 方法
  9. FindFirstFile和FindNextFile
  10. 学习spring第一天