- 浏览: 555043 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
hdblocal_:
为什么messageReceived之后,再encode,有点 ...
MINA框架使用总结 -
andey007518:
MINA框架使用总结 -
ymm8505:
我自己的理解 CopyOnWriteArrayList 这个 ...
ArrayList遍历的同时删除 -
spring_springmvc:
可以参考最新的文档:如何在eclipse jee中检出项目并转 ...
Eclipse快捷键-方便查找 -
netwelfare:
文章讲解的不够详细,ArrayList在遍历的同时如果去删除或 ...
ArrayList遍历的同时删除
这个问题网上一直没有搜到很详细的解释,也可能是高人的解释不符合我的理解方式。所以自己到网上搜集了写资料再加自己的想法,随便写了点东西发到论坛上,希望大家给予修正意见,看我是否理解对了。
一般servlet在jvm中只有个对象,当多个请求来请求一个jsp页面的时候,实际上都是调用这个jsp编译好的servlet类doPost或者doGet方法。
现在我就模拟一个servlet的调用过程
new Runnalbe{ public run(){ Request requset = new Request(); Resposne response = new Response(); //servlet对象只有一个,是容器自动生成的,这里模拟一个servlet的调用过程。 servlet.doPost (request,response); } }
当有多个请求过来的时候,相当于多个线程来执行这段代码。上面那个servlet的实现类HelloServlet:
public class HelloServlet extends HttpServlet { private int j =0; public void doPost(HttpServletRequest request, HttpServletResponse response){ int i=0; i++; j++; //这里的i和j那个是线程安全的那个不是呢,后面我们将从线程的堆栈,和jvm的堆的概念来解释这个问题 //request 和 response 对象是不是线程安全的 } }
JVM是基于堆栈的虚拟机.JVM为每个新创建的线程都分配一个堆栈(这里的堆栈不是指堆).也就是说,对于一个Java程序来说,它的运行
就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。
我们知道,某个线程正在执行的方法称为此线程的当前方法.我们可能不知道,当前方法使用的帧称为当前帧。当线程激活一个
Java方法,JVM就会在线程的Java堆栈里新压入一个帧。这个帧自然成为了当前帧.在此方法执行期间,这个帧将用来保存参数,局部变量,中间计算过程和其他数据.这个帧在这里和编译原理中的活动纪录的概念是差不多的。
这里还要补充一下堆的概念:
堆(heap)是放实例和数组的,JAVA里面没有全局变量这个概念,所有变量都是以类的属性或者参数等形式存在的。GC是自动回收.但是数组和类的引用是放在堆栈中。
学过汇编的可能都知道,数据是是存储在栈内的,执行的代码逻辑是可以共用的。当多个线程来访问同一个方法的时候,共享同一段代码逻辑,但是方法对应的数据是存储在各自的堆栈(stack)中,如局部变量和参数还有对象的引用(局部变量和参数也可能是对象的引用)。所以多线程并发的情况下,出现不同步的现象主要是因为各自堆栈存放的某些数据是共享的,说白了就是同一个数据的引用(不是copy)被存放在不同的堆栈中。
例如类X的对象A被多个线程访问,他的引用被保存在多个线程的堆栈中,当多个线程访问A对象的某个属性b的时候如果不加锁就会出现不同步的现象。所以为了避免这种情况发生一是加锁,二就是为每个线程都生成一个类X的对象,这样每个线程的堆栈中存放的类X引用所对应的堆中的对象都不一样,当然就不存在共享的问题。
现在我们回到开始那个例子,可以很好的分析出参数request,respone,i是线程安全的,而j是线程不安全的;
为什么?request,respone是线程安全的是因为每个线程对应的request,respone对象都是不一样的,不存在共享问题。i是线程安全的是应为i是局部变量,每个线程的堆栈中存放的值也是各自独立的。
j线程不安全是应为它是类HelloServlet的属性,找了很多资料都不能说清楚它到底放在那里,从实际效果来看,它是不安全的,所以应该是放在和类对象一起放在堆里面的,堆里面估计是复制了一份过来,因为HelloServlet对多个线程而言只有
一个实例,所以存在共享问题。
评论
servlet是单实例多线程运行方式,所以对象变量线程不安全,局部变量线程安全
同意! local variable不存在race condition, 但是instance variable存在race condition.
请诸位看这里,
http://book.javanb.com/java-concurrency-in-Practice/ch02lev1sec2.html
The definition of race condition,
The possibility of incorrect results in the presence of unlucky timing is so important in concurrent programming that it has a name: a race condition.
servlet是单例的还是很有道理的!
所以基础数据声明后,不管怎么赋值,都不会有线程问题(int i=1;int j=i)两个int 类型的数据根本就是2个数据体。
局部变量本来就是在某个线程的生命周期内声明的变量,如果不用特别的方法保存它,其他线程根本没办法引用到它,所以也就没有线程同步的问题存在
而引用同一个对象,修改得是同一个堆中的数据,线程同步腐蚀就出现了,如果没有状态数据,被使用对象也就没有被线程修改得可能,也就没有线程安全问题
说的不错,很认同,如《 进行运算而产生的中间结果会放在cpu的寄存器中》 这句话,比如说j=5;j在第一个线程自增后的结果6保存在CPU的临时寄存器中,假如寄存器自增的值6没有及时回写到内存中去,而同时又有另一个线程执行了此代码,则刚才有第一个线程自增的结果将被第二个线程清洗掉,然后后一个线程在j原先的基础上5上自增1为6,回写到内存。退出代码,假如此时第一个线程被唤醒,再次见寄存器中的值写入到内存中,还是6。经过了两次自增并应该是7,但内存中的值是6,就导致了线程不同步,主要是由于自增运算造成的,而基础数据的任何的赋值操作是不会导致线程安全问题。
如果一个对象下一刻的值 需要依赖原来的值,
就会在多线程下有同步的问题
所以基础数据声明后,不管怎么赋值,都不会有线程问题(int i=1;int j=i)两个int 类型的数据根本就是2个数据体。
局部变量本来就是在某个线程的生命周期内声明的变量,如果不用特别的方法保存它,其他线程根本没办法引用到它,所以也就没有线程同步的问题存在
而引用同一个对象,修改得是同一个堆中的数据,线程同步腐蚀就出现了,如果没有状态数据,被使用对象也就没有被线程修改得可能,也就没有线程安全问题
说的不错,很认同,如《 进行运算而产生的中间结果会放在cpu的寄存器中》 这句话,比如说j=5;j在第一个线程自增后的结果6保存在CPU的临时寄存器中,假如寄存器自增的值6没有及时回写到内存中去,而同时又有另一个线程执行了此代码,则刚才有第一个线程自增的结果将被第二个线程清洗掉,然后后一个线程在j原先的基础上5上自增1为6,回写到内存。退出代码,假如此时第一个线程被唤醒,再次见寄存器中的值写入到内存中,还是6。经过了两次自增并应该是7,但内存中的值是6,就导致了线程不同步,主要是由于自增运算造成的,而基础数据的任何的赋值操作是不会导致线程安全问题。
servlet是否线程安全取决容器的实现, 一般来说, servlet不是线程安全的, 你自要实现一个也无所谓。
共享会不会造成线程安全也是不对的.
确切的说, 如果一个对象的实例, 在多线程环境下, 如果API CALL会有状态的, 那么他一般就不是线程安全的。
简单明了,同意
servlet是否线程安全取决容器的实现, 一般来说, servlet不是线程安全的, 你自要实现一个也无所谓。
共享会不会造成线程安全也是不对的.
确切的说, 如果一个对象的实例, 在多线程环境下, 如果API CALL会有状态的, 那么他一般就不是线程安全的。
简单明了,同意
我先前刚好以为的和你说的相反,我以为容器为每个请求都创建一个新的servlet实例,这种情况下是线程安全的,如果实现singleModel什么的接口,系统将只创建一个servlet实例,分配给所有线程,这样就不安全了,看这个名字singleXX就不像是什么安全的东西,在servlet2.0版本中就不建议使用了,不过是为了节省内存开销。。
现在看大家都这么说,我估计是不是我的想法错了。。
servlet是单实例多线程运行方式,所以对象变量线程不安全,局部变量线程安全
说的很对,受教了。
没错,同一个servlet对于不同用户的请求使用不同的线程处理
servlet是否线程安全取决容器的实现, 一般来说, servlet不是线程安全的, 你自要实现一个也无所谓。
共享会不会造成线程安全也是不对的.
确切的说, 如果一个对象的实例, 在多线程环境下, 如果API CALL会有状态的, 那么他一般就不是线程安全的。
准确点说是堆数据共享
2)例如类X的对象A被多个线程访问,他的引用被保存在多个线程的堆栈中,
一个java虚拟机中只有一个堆被多个线程共享
我也没有验证过
而servlet是否是单例取决于容器的实现
一般来说不是单例的
不对吧,一般来说Servlet都是单例的。
public class TestServletSingle extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } response.getOutputStream().println(this.hashCode()); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
你在5秒内打开N个浏览器窗口试试,返回的都是相同的Hashcode。只有在context reload以后,Hashcode才发生变化。因为原来的servlet object销毁了,容器又新建了一个。
然而,Servlet的单例不由class来决定,而是由您在web.xml里配置的servlet-name来决定。也就是说每一个servlet-name只有1个单例。当你有3个不同的serlvet-name指定了相同的1个servlet-class时,容器会产生3个不同的servlet object。只有3个。
其实就是一个线程安全的问题
和servlet没有关系
你这个j是否线程安全取决于你的servlet是否是同一个对象
而servlet是否是单例取决于容器的实现
一般来说不是单例的
发表评论
-
为何在使用CMS gc算法时会出现连续两次full gc
2011-09-01 11:04 4977现象: jstat -gcutil pid 1000观察到 ... -
配置filter拦截forward之类的内部转发
2011-02-18 17:19 6034在servlet-2.3中,Filter会过滤一切请求,包括服 ... -
request.getRequestURI 与request.getServletPath() 区别
2011-02-16 19:38 7851路径:resin/webapps/my_proj/test/r ... -
ConcurrentHashMap中的remove方法的bug
2010-04-30 11:48 5825最近研究了一下 ConcurrentHashMap中源码发现j ... -
搭建Android开发环境
2010-04-05 23:22 1554在eclipse上安装Android 1.安装eclipse ... -
IoServer源代码阅读笔记
2009-08-23 21:57 2159NIO:写事件要尽量早的被注销. 1,IOServer用一 ... -
一个webapp目录下部署多个web应用
2009-08-21 10:34 2166在同一个resin下的webapp目录部署多个web应用,发现 ... -
java 的深度克隆
2009-07-01 20:07 1813只有实现了cloneable接口才算是真正的深度克隆. 在复 ... -
try finally return
2009-03-20 19:21 1260class Entry { ... -
String和==号的问题
2009-03-09 19:45 1241String name = "you" ... -
Bit数组
2009-01-20 18:56 2906public class BitArray{//用byte数组 ... -
关于Java占用内存的研究 (转载请注明作者zms)
2009-01-20 15:28 3016版权声明:转载时请以 ... -
几种通讯协议的比较
2009-01-20 15:26 5360一、综述 本文比较了RMI ... -
java基础知识总结
2009-01-06 00:50 2863http://wiki.caucho.com/Hessian_ ... -
Java基础-关于session的详细解释
2008-12-01 23:49 1393一、术语session 在我的经验里,session这个词 ... -
关于大量缓存对象回收的思考
2008-12-01 15:34 2674前几天面试,被问到了一个问题,如果当前有数亿条记录,但是缓存最 ... -
java 快速排序demo
2008-11-29 19:52 2070快速排序算法思想如下,先选取一个元素作为基准,然后根据这个基准 ... -
java 实现简单的文件拷贝
2008-11-26 17:36 6280昨天面试,面试官要我在黑板上写个java文件复制的代码,但是一 ... -
HashMap的遍历效率讨论
2008-11-26 11:31 3696经常遇到对HashMap中的key和value值对的遍历操作 ... -
Java ArrayList 实现
2008-11-25 23:02 3761ArrayList是List接口的一个可变长数组实现。实现了 ...
相关推荐
Servlet 线程安全问题 Servlet 线程安全问题是指在使用 Servlet 编程时,如果不注意多线程安全性问题,可能会导致难以发现的错误。Servlet/JSP 技术由于其多线程运行而具有很高的执行效率,但这也意味着需要非常...
Servlet线程安全问题详解 在Java Web开发中,Servlet是一个重要的组件,用于处理HTTP请求。然而,Servlet在多线程环境下的线程安全问题是一个不容忽视的话题。在Servlet的生命周期中,Tomcat容器会根据需求实例化...
#### 三、Servlet线程安全问题分析 线程安全问题是由于Servlet中实例变量的使用不当导致的。在多线程环境中,如果多个线程同时修改相同的实例变量,则可能导致数据不一致性问题。例如,在上面给出的`ConcurrentTest...
#### 一、理解Servlet线程安全问题 Servlet是Java平台上的一个重要的Web组件模型,用于处理HTTP请求并返回响应。每当客户端向服务器发送请求时,服务器会创建一个线程来处理这个请求。由于Servlet是单例模式实现的...
### Servlet线程安全问题实例分析 以一个简单的Servlet为例,该Servlet接收用户请求,读取参数,并输出结果: ```java public class Test extends HttpServlet { private static final long serialVersionUID = 1...
Servlet和Struts Action是两种常见的Java Web开发组件,它们在多线程环境下运行时可能存在线程安全问题。线程安全是指在多线程环境中,一个类或者方法能够正确处理多个线程的并发访问,保证数据的一致性和完整性。 ...
#### 三、Servlet线程安全问题 线程安全问题主要发生在Servlet中使用实例变量时。当多个线程并发访问同一个Servlet实例时,如果这些线程试图同时修改实例变量,就可能发生数据不一致的情况。以下通过一个具体的示例...
在讨论了Servlet线程安全问题的代码实现后,让我们来总结一下Servlet线程安全问题的几个要点: 1. 线程安全问题产生的原因:在多用户环境下,多个线程同时访问和修改共享资源(如Servlet中的`ticket`变量)时,如果...
Servlet是一种线程不安全的组件,它的线程不安全性体现在多线程环境下共享一个实例变量,导致线程安全问题。下面我们将从Servlet的工作原理说起,详细解释Servlet接收和响应客户请求的过程,并探讨Servlet线程不安全...
Servlet线程同步计数器实验是Java Web开发中一个重要的实践课题,主要涉及到Servlet容器如何处理并发请求以及如何确保在多线程环境下的数据一致性。在这个实验中,我们将深入理解Servlet生命周期、线程模型以及线程...
4. **避免在Servlet中创建额外线程**:由于Servlet本身已具备多线程特性,额外创建线程可能会引入复杂的线程安全问题,除非有特殊需求。 5. **对外部资源的线程安全操作**:在多个Servlet中对同一外部资源(如文件...
在这个场景下,可能的问题可能是由于Servlet在处理高并发请求时,由于多线程并发访问共享资源导致的线程安全问题。 在Java Web环境中,Servlet容器(如Tomcat、Jetty等)会为每个HTTP请求创建一个新的线程来处理,...
5. **Servlet线程安全问题**: Servlet容器通常会为每个请求创建一个新的线程,因此,Servlet实例默认是线程安全的。但是,如果在Servlet中定义了成员变量,需要考虑多线程环境下可能产生的并发问题。 6. **...