java servlet 多线程_Servlet的多线程和线程安全
线程安全
首先说明一下对线程安全的讨论,哪种情况我们可以称作线程安全?
网上对线程安全有很多描述,我比较喜欢《Java并发编程实战》给出的定义,“当多个线程访问某个类时,不管运行时环境采用何种调度方式,或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的”。
Servlet的调用过程和生命周期
Servlet的生命周期
Servlet是运行在Servlet容器中的,常用的tomcat、jboss、weblogic都是Servlet容器,其生命周期是由容器来管理。Servlet的生命周期通过java.servlet.Servlet接口中的init()、service()、和destroy()方法表示。Servlet的生命周期有四个阶段:加载并实例化、初始化、请求处理、销毁。
加载并实例化
Servlet容器负责加载和实例化Servelt。当Servlet容器启动时,或者在容器检测到需要这个Servlet来响应第一个请求时,创建Servlet实例。当Servlet容器启动后,Servlet通过类加载器来加载Servlet类,加载完成后再new一个Servlet对象来完成实例化。
初始化
在Servlet实例化之后,容器将调用init()方法,并传递实现ServletConfig接口的对象。在init()方法中,Servlet可以部署描述符中读取配置参数,或者执行任何其他一次性活动。在Servlet的整个生命周期类,init()方法只被调用一次。
请求处理
当Servlet初始化后,容器就可以准备处理客户机请求了。当容器收到对这一Servlet的请求,就调用Servlet的service()方法,并把请求和响应对象作为参数传递。当并行的请求到来时,多个service()方法能够同时运行在独立的线程中。通过分析ServletRequest或者HttpServletRequest对象,service()方法处理用户的请求,并调用ServletResponse或者HttpServletResponse对象来响应。
销毁
一旦Servlet容器检测到一个Servlet要被卸载,这可能是因为要回收资源或者因为它正在被关闭,容器会在所有Servlet的service()线程之后,调用Servlet的destroy()方法。然后,Servlet就可以进行无用存储单元收集清理。这样Servlet对象就被销毁了。这四个阶段共同决定了Servlet的生命周期。
Servlet的调用过程
1.客户端通过发送请求给Tomcat,Tomcat发送客户端的请求页面给客户端。
2.用户对请求页面进行相关操作后将页面提交给Tomcat,Tomcat将其封装成一个HttpRequest对象,然后对请求进行处理,。
3.Tomcat截获请求,根据action属性值查询xml文件中对应的servlet-name,再根据servlet-name查询到对应的java类(如果是第一次,Tomcat则会将servlet编译成java类文件,所以如果servlet有很多的话第一次运行的时候程序会比较慢)。
4.Tomcat实例化查询到的java类,注意该类只实例化一次。
5.调用java类对象的service()方法(如果不对service()方法进行重写则根据提交的方式来决定执行doPost()方法还是doGet()方法)。
6.通过request对象取得客户端传过来的数据,对数据进行处理后通过response对象将处理结果写回客户端。
Servlet是线程安全的吗?
从上面Servlet的调用过程可以看出,当客户端第一次请求Servlet的时候,tomcat会根据web.xml配置文件实例化servlet,
当又有一个客户端访问该servlet的时候,不会再实例化该servlet,也就是多个线程在使用这个实例。
JSP/Servlet容器默认是采用单实例多线程(这是造成线程安全的主因)方式处理多个请求的,这种默认以多线程方式执行的设计可大大降低对系统的资源需求,提高系统的并发量及响应时间。
Servlet本身是无状态的,一个无状态的Servlet是绝对线程安全的,无状态对象设计也是解决线程安全问题的一种有效手段。
所以,servlet是否线程安全是由它的实现来决定的,如果它内部的属性或方法会被多个线程改变,它就是线程不安全的,反之,就是线程安全的。
下面这个示例来自《Java并发编程实战》,在竞态条件下存在线程不安全。
public class UnsafeCountingFactorizer implements Servlet{
private long count=0;
public long getCount(){
return count;
}
@Override
public void service(ServletRequest req, ServletResponse resp)
throws ServletException, IOException {
BigInteger i=extractFromRequest();
BigInteger[] factors=factor(i);
++count;
}
}
递增操作count++并非是原子操作,它包含了三个独立的操作:读取count的值,将值加1,
然后将计算结果写入coune,这是一个“读取-修改-写入”的操作序列,并且其结果状态依赖于之前的状态。在执行时序不同的情况下,可能会产生错误。
影响Servlet线程安全的因素
多线程下每个线程对局部变量都会有自己的一份copy,这样对局部变量的修改只会影响到自己的copy而不会对别的线程产生影响,所以这是线程安全的。
但是对于实例变量来说,由于servlet在Tomcat中是以单例模式存在的,所有的线程共享实例变量。多个线程对共享资源的访问就造成了线程不安全问题。
如何控制Servlet的线程安全性?
避免使用实例变量
避免使用非线程安全的集合
在多个Servlet中对某个外部对象(例如文件)的修改是务必加锁(Synchronized,或者ReentrantLock),互斥访问。
属性的线程安全:ServletContext、HttpSession是线程安全的;ServletRequest是非线程安全的。
设计线程安全的Servlet
1.实现 SingleThreadModel 接口
该接口指定了系统如何处理对同一个Servlet的调用。如果一个Servlet被这个接口指定,那么在这个Servlet中的service方法将不会有两个线程被同时执行,当然也就不存在线程安全的问题。但是,如果一个Servlet实现了SingleThreadModel接口,Servlet引擎将为每个新的请求创建一个单独的Servlet实例,这将引起大量的系统开销,在现在的Servlet开发中基本看不到SingleThreadModel的使用,这种方式了解即可,尽量避免使用。
public class XXXXX extends HttpServlet implements SingleThreadModel {
…………
}
2.同步对共享数据的操作
使用synchronized 关键字能保证一次只有一个线程可以访问被保护的区段,可以通过同步块操作来保证Servlet的线程安全。如果在程序中使用同步来保护要使用的共享的数据,也会使系统的性能大大下降。这是因为被同步的代码块在同一时刻只能有一个线程执行它,使得其同时处理客户请求的吞吐量降低,而且很多客户处于阻塞状态。另外为保证主存内容和线程的工作内存中的数据的一致性,要频繁地刷新缓存,这也会大大地影响系统的性能。所以在实际的开发中也应避免或最小化Servlet 中的同步代码。
同步代码:
Public class XXXXXX extends HttpServlet {
synchronized (this){XXXX}
}
3.避免使用实例变量
线程安全问题很大部分是由实例变量造成的,只要在Servlet里面的任何方法里面都不使用实例变量,那么该Servlet就是线程安全的。
在Servlet中避免使用实例变量是保证Servlet线程安全的最佳选择。
Java 内存模型中,方法中的临时变量是在栈上分配空间,而且每个线程都有自己私有的栈空间,所以它们不会影响线程的安全。
参考:
相关文章:

JMeter 聚合报告之 90% Line 参数说明
其实要说明这个参数的含义非常简单,可能你早就知道他的含义,但我对这个参数一直有误解,而且还一直以为是“真理”,原于一次面试,被问到了这个问题,所以引起我这个参数的重新认识。 先说说我错误的认识&…

CCF-碰撞的小球
问题描述数轴上有一条长度为L(L为偶数)的线段,左端点在原点,右端点在坐标L处。有n个不计体积的小球在线段上,开始时所有的小球都处在偶数坐标上,速度方向向右,速度大小为1单位长度每秒。当小球到达线段的端…

C语言网络编程:多路IO select实现多客户端
文章目录阻塞式的服务器程序多线程服务器程序非阻塞式服务器程序基于事件响应的服务器程序事件响应服务器程序的实现select阻塞式的服务器程序 我们接触过最多的最基础的网络通信模型为TCP/UDP通信模型,以下为TCP通信模型的基本流程C语言网络编程:TCP客…

MVC 中的 ViewModel
此文章总结自:http://rachelappel.com/use-viewmodels-to-manage-data-amp-organize-code-in-asp.net-mvc-applications ViewModel 这个概念不只是在在MVC模式中有,你会在很多关于MVC、MVP、MVVM的文章中见到这个说法,并且这个概念在任何技术…

java udp tcp协议_【java】TCP和UDP传输协议
TCP协议和UDP协议的比较TCP的全称是Transmission Control Protocol (传输控制协议)传输控制协议,是一种面向连接的协议,类似打电话在通信的整个过程中保持连接保证了数据传递的可靠性和有序性是一种全双工的字节流通信方式服务器压力比较大,资…

dot3_bump_mapping
为什么80%的码农都做不了架构师?>>> //----------------------------------------------------------------------------- // Name: ogl_dot3_bump_mapping.cpp // Author: Kevin Harris // Last Modified: 04/21/05 // Descript…

WPF入门教程-转载
最近为了做炫酷的UI,了解了WPF,之前一直是使用winform的,界面也是古老的不行。在园里找到了一个大佬以前写的教程,备注一下。按照系列教程走下来,可以直接上手了。备忘传送门>>>link:DotNet菜园-W…

记一次shell脚本推后台stopped的问题
我们知道linux 下shell可以被分为交互式脚本和非交互式脚本。 交互式脚本即 输入命令之后shell会等待你的输入,当你输入之后命令会被立即提交从而执行。这个时候我们常见的终端bash,以及login提示等都是交互式命令。 非交互式脚本即shell解释器不需要等待…

封装,继承,多态
一、封装: 封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类)。被封装的对象通常被称为抽象数据类型。 封装的意义: 封装的意义在于保护或者防止代码(数据…

java将一个数转成36进制的数_编程实现将一个N进制数转换成M进制数。
python: 手写算法版: def conversion_num(num, src, dest): rtn # 1、校验源和目标是否相同 if src dest: rtn num # 2、转成10进制# if src ! 10: num_str str(num) num_str num_str[::-1] exe_num 0 dec_num 0 for num_char in num_str: # 十六进制处理 i…

iOS之Storyboard导航大揭秘(1)
本文使用的软件版本: IOS:6.1 XCode:4.6 Storyboard(故事板)是XCode4.2才开始支持的,为了使设计View更容易。尽管用以前的nib(xib)拖拖拽拽也没问题,不过却需要 在各种文…

nginx的gzip压缩功能
我们在开发网站的时候,应该要考虑到pv,因为pv比较大可能会造成服务器带宽不够用,进而导致用户体验变差。 这个时候我们就可以考虑用nginx的gzip功能。 在nginx中开启gzip压缩功能很简单,之需要在nginx的配置文件nginx.conf中配置以…

C语言的单链表逆序和指定范围逆序
文章目录前言逆序指定范围逆序源码实现前言 关于链表的逆置,是考察对链表指针的理解。知道了如何不实用额外空间,同时使用O(n)复杂度对链表进行逆序之后将会对链表有好理解。 同时关于如何在指定范围内对链表逆置同样可以进一步加深理解 逆序 基本过程…

mysql udf 性能_适当的mysql udf
问题不在于参数的类型,而是在调用str_ucwords_init时它是NULL(因为在检索任何行之前调用了str_ucwords_init).要使str_ucwords与字段一起使用,您必须通过在_init函数中将initid-> maybe_null设置为1并在str_ucwords中将* null_value设置为1(并且结果为NULL,尽管这可能不是必…

让Windows7运行速度更快的BIOS优化设置教程
和以前使用WindowsXP一样,很多用户都在设法提高windows7的系统运行速速,比较常见的方法大多是对系统服务进行优化,去掉一些可有可无的系统服务,还有就是优化资源管理器菜单等。除此之外,还有一些“不常见的偏方”&…

开源 免费 java CMS - FreeCMS1.2-功能说明-网上调查
2019独角兽企业重金招聘Python工程师标准>>> 下载地址:http://code.google.com/p/freecms/ 网上调查 从FreeCMS 1.2 开始支持 Admin和站点管理员可以管理站点下所有网上调查,普通用户只可管理自己添加的网上调查。 1. 网上调查管理 从左…

Python 之 杂谈(迭代器iter)、偏函数
1、 l [1,2,3,b,5,6] def func():return l.pop() x iter(func,b) print(x.__next__()) print(x.__next__()) print(x.__next__())执行结果: 遇到“b”就停下 2、偏函数 from functools import partial def add(x,y):return xy func partial(add,1)#将1固定传给x…

C语言的单链表创建:头插法/尾插法
文章目录前言链表头插法链表尾插法源码实现前言 接下来一段时间,将对数据结构进行复习,总的来说数据结构自大学之后忘记得有点吓人,为了防止脑容量本就小得脑袋更小,必须得持续性得温故了。 链表数据结构得提出 是为了弥补数组上…

java配置文件实现方式_java相关:详解Spring加载Properties配置文件的四种方式
java相关:详解Spring加载Properties配置文件的四种方式发布于 2020-4-29|复制链接摘记: 一、通过 context:property-placeholder 标签实现配置文件加载1、用法示例: 在spring.xml配置文件中添加标签..一、通过 context:property-placeholder 标签实现配置…

objective-c abort() 与 exit() 函数的区别
exit()函数 调用exit会让用户感觉程序崩溃了,不会有按Home键返回时的平滑过渡和动画效果;另外,使用exit可能会丢失数据,因为调用exit并不会调用-applicationWillTerminate:方法和UIApplicationDelegate方法; abort() a…

用户、组的管理常用到的命令介绍
在LINUX系统管理中,我们经常添加删除修改用户和组的信息,所以我们来学习下创建删除修改用户和组 下面我们就来简单的说下什么是组、什么是用户的概念? 用户: 其实简单的理解就是文件或者目录创建的一种标识。 组: 组简…

react生命周期函数
在react中,生命周期函数指的是组件在加载前,加载后,以及组件更新数据和组件销毁时触发的一系列方法。通常分为以下几类: 组件加载的时候触发的函数:constructor 、componentWillMount、 render 、componentDidMount 组…

C语言的单链表求交点
单链表求交点,问题如下: 使用o(1)的空间复杂度,求两个链表相交的时候的交点,这个思想就类似于使用o(1)的空间复杂度和o(n)的时间复杂度来求链表的第k个节点。 过程如下: 获取两个链表的长度将较长的链表移动和短链表…

jquery中如何以逗号分割字符串_百度知道
jquery中如何以逗号分割字符串_百度知道javascript本身就是带split方法的定义和用法split() 方法用于把一个字符串分割成字符串数组。语法stringObject.split(separator,howmany)参数 描述separator 必需。字符串或正则表达式,从该参数指定的地方分割 stringObject。…

mysql 前台启动_从Windows命令行启动MySQL
可以从命令行手动启动MySQL服务器。可以在任何版本的Windows中实现。要想从命令行启动mysqld服务器,你应当启动控制台窗口(或“DOS window”)并输入命令:C:\> C:\Program Files\MySQL\MySQL Server 5.0\bin\mysqld根据系统中MySQL安装位置…

设置datagridview的数据源为(DATASET)SQL查寻结果
private void button5_Click(object sender, EventArgs e)02 {03 if (MessageBox.Show("确认删除该行吗?", "删除", MessageBoxButtons.YesNo, MessageBoxIcon.Question) DialogResult.Yes )04 {05 SqlConnection conn new SqlConnection();0…

vim中文手册
http://vimcdoc.sourceforge.net/doc/help.html转载于:https://www.cnblogs.com/answercard/p/10125611.html

C语言单链表求环,并返回环的起始节点
若链表中存在环,找出其中的环所在的节点,否则,返回NULL 在没有C set容器的优势前提下,我们对这样的环型的寻找以及定位可以利用快慢指针来实现。 有环的存在,类似与操场跑圈,必然存在快慢之分。有了快慢&a…

CSS3无前缀脚本prefixfree.js与Animatable使用介绍
要求 必备知识 本文要求基本了解 JAVASCRIPT 和 和 CSS3 基本知识。 运行环境 桌面端:IE9 ,Opera 10,火狐3.5 ,Safari 4和Chrome浏览器;移动端:移动Safari,Android浏览器,Chrome浏览器和Opera Mobile。 演示地址 演示…

mysql的优化之table_open_cache 篇_mysql性能优化之table_open_cache
表现:数据库查询效率慢,show processlist 发现比较多的查询正在opening table。进一步确认,执行以下语句:mysql> show global status like open%tables%;------------------------| Variable_name | Value |----------------…