- 浏览: 155894 次
- 性别:
- 来自: 西安
文章分类
最新评论
-
atgfss:
采用在cookies中保存用户名和sessionid的这种方式 ...
自动登录 -
liumm19870913:
对有输入参数过程的调用
我试过那代码 , 有问题呀,funct ...
oracle 存储过程调用 -
zdsyouxiang:
内容很全面!
认识多任务、多进程、单线程、多线程
转自 http://www.newasp.net/tech/java/15350.html
在编写Servlet/JSP程序时,对实例变量一定要小心使用。因为实例变量是非线程安全的。
在Servlet/JSP中,变量可以归为下面的几类:
1. 类变量
request,response,session,config,application,以及JSP页面内置的page, pageContext。
其中除了application外,其它都是线程安全的。
2. 实例变量
实例变量是实例所有的,在堆中分配。在Servlet/JSP容器中,一般仅实例化一个Servlet/JSP实例,
启动多个该实例的线程来处理请求。而实例变量是该实例所有的线程所共享,所以,实例变量不是线程安全的。
3. 局部变量
局部变量在堆栈中分配,因为每一个线程有自己的执行堆栈,所以,局部变量是线程安全的。
二、在Servlet/JSP中的多线程同步问题
在JSP中,使用实例变量要特别谨慎。首先请看下面的代码:
在这个页面中,首先定义了两个实例变量,username和password。然后在从request中获取这两个参数,并调用showUserInfo()方法将请求用户的信息回显在该客户的浏览器上。在一个用户访问是,不存在问题。但在多个用户并发访问时,就会出现其它用户的信息显示在另外一些用户的浏览器上的问题。这是一个严重的问题。为了突出并发问题,便于测试、观察,我们在回显用户信息时执行了一个模拟的费时操作,比如,下面的两个用户同时访问(可以启动两个IE浏览器,或者在两台机器上同时访问):
如果a点击链接后,b再点击链接,那么,a将返回一个空白屏幕,b则得到a以及b两个线程的输出。请看下面的屏幕截图:
图1:a的屏幕
图2:b的屏幕
从运行结果的截图上可以看到,Web服务器启动了两个线程分别来处理来自a和b的请求,但是在a却得到一个空白的屏幕。这是因为上面程序中的output, username和password都是实例变量,是所有线程共享的。在a访问该页面后,将output设置为a的输出,username,password分别置为a的信息,而在a执行printUserInfo()输出username和password信息前,b又访问了该页面,把username和password置为了b的信息,并把输出output指向到了b。随后a的线程打印时,就打印到了b的屏幕了,并且,a的用户名和密码也被b的取代。请参加下图所示:
图3:a、b两个线程的时间线
而实际程序中,由于设置实例变量,使用实例变量这两个时间点非常接近,所以,像本例的同步问题并没有这么突出,可能会偶尔出现,但这却更加具有危险性,也更加难于调试。
同样,对于Servlet也存在实例变量的多线程问题,请看上面页面的Servlet版:
三、解决方案
1. 以单线程运行Servlet/JSP
在JSP中,通过设置:<%@ page isThreadSafe="false" %>,在Servlet中,通过实现javax.servlet.SingleThreadModel,此时Web容器将保证JSP或Servlet实例以单线程方式运行。
重要提示:在测试中发现,Tomcat 4.1.17不能正确支持isThreadSafe属性,所以,指定isTheadSafe为false后,在Tomcat 4.1.17中仍然出现多线程问题,这是Tomcat 4.1.17的Bug。在Tomcat 3.3.1和Resin 2.1.5中测试通过。
2. 去除实例变量,通过参数传递
从上面的分析可见,应该在Servlet/JSP中尽量避免使用实例变量。比如,下面的修正代码,去除了实例变量,通过定义局部变量,并参数进行传递。这样,由于局部变量是在线程的堆栈中进行分配的,所以是线程安全的。不会出现多线程同步的问题。代码如下:
注:有的资料上指出在printUserInfo()方法或者实例变量的相关操作语句上使用synchronized关键字进行同步,但这样并不能解决多线程的问题。因为,这样虽然可以使对实例变量的操作代码进行同步,但并不能阻止一个线程使用另外一个线程修改后的“脏的”实例变量。所以,除了降低运行效率外,不会起到预期效果。
在编写Servlet/JSP程序时,对实例变量一定要小心使用。因为实例变量是非线程安全的。
在Servlet/JSP中,变量可以归为下面的几类:
1. 类变量
request,response,session,config,application,以及JSP页面内置的page, pageContext。
其中除了application外,其它都是线程安全的。
2. 实例变量
实例变量是实例所有的,在堆中分配。在Servlet/JSP容器中,一般仅实例化一个Servlet/JSP实例,
启动多个该实例的线程来处理请求。而实例变量是该实例所有的线程所共享,所以,实例变量不是线程安全的。
3. 局部变量
局部变量在堆栈中分配,因为每一个线程有自己的执行堆栈,所以,局部变量是线程安全的。
二、在Servlet/JSP中的多线程同步问题
在JSP中,使用实例变量要特别谨慎。首先请看下面的代码:
// instanceconcurrenttest.jsp <%@ page contentType="text/html;charset=GBK" %> <%! //定义实例变量 String username; String password; java.io.PrintWriter output; %> <% //从request中获取参数 username = request.getParameter("username"); password = request.getParameter("password"); output = response.getWriter(); showUserInfo(); %> <%! public void showUserInfo() { //为了突出并发问题,在这儿首先执行一个费时操作 int i =0; double sum = 0.0; while (i++ < 200000000) { sum += i; } output.println(Thread.currentThread().getName() + "<br>"); output.println("username:" + username + "<br>"); output.println("password:" + password + "<br>"); } %>
在这个页面中,首先定义了两个实例变量,username和password。然后在从request中获取这两个参数,并调用showUserInfo()方法将请求用户的信息回显在该客户的浏览器上。在一个用户访问是,不存在问题。但在多个用户并发访问时,就会出现其它用户的信息显示在另外一些用户的浏览器上的问题。这是一个严重的问题。为了突出并发问题,便于测试、观察,我们在回显用户信息时执行了一个模拟的费时操作,比如,下面的两个用户同时访问(可以启动两个IE浏览器,或者在两台机器上同时访问):
a: http://localhost:8080/instanceconcurrenttest.jsp?username=a&password=123 b: http://localhost:8080/instanceconcurrenttest.jsp?username=b&password=456
如果a点击链接后,b再点击链接,那么,a将返回一个空白屏幕,b则得到a以及b两个线程的输出。请看下面的屏幕截图:
图1:a的屏幕
图2:b的屏幕
从运行结果的截图上可以看到,Web服务器启动了两个线程分别来处理来自a和b的请求,但是在a却得到一个空白的屏幕。这是因为上面程序中的output, username和password都是实例变量,是所有线程共享的。在a访问该页面后,将output设置为a的输出,username,password分别置为a的信息,而在a执行printUserInfo()输出username和password信息前,b又访问了该页面,把username和password置为了b的信息,并把输出output指向到了b。随后a的线程打印时,就打印到了b的屏幕了,并且,a的用户名和密码也被b的取代。请参加下图所示:
图3:a、b两个线程的时间线
而实际程序中,由于设置实例变量,使用实例变量这两个时间点非常接近,所以,像本例的同步问题并没有这么突出,可能会偶尔出现,但这却更加具有危险性,也更加难于调试。
同样,对于Servlet也存在实例变量的多线程问题,请看上面页面的Servlet版:
// InstanceConcurrentTest.java import javax.servlet.*; import javax.servlet.http.*; import java.io.PrintWriter; public class InstanceConcurrentTest extends HttpServlet { String username; String password; PrintWriter out; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,java.io.IOException { //从request中获取参数 username = request.getParameter("username"); password = request.getParameter("password"); System.out.println(Thread.currentThread().getName() + " | set username:" + username); out = response.getWriter(); showUserInfo(); } public void showUserInfo() { //为了突出并发问题,在这儿首先执行一个费时操作 int i =0; double sum = 0.0; while (i++ < 200000000) { sum += i; } out.println("thread:" + Thread.currentThread().getName()); out.println("username:"+ username); out.println("password:" + password); } }
三、解决方案
1. 以单线程运行Servlet/JSP
在JSP中,通过设置:<%@ page isThreadSafe="false" %>,在Servlet中,通过实现javax.servlet.SingleThreadModel,此时Web容器将保证JSP或Servlet实例以单线程方式运行。
重要提示:在测试中发现,Tomcat 4.1.17不能正确支持isThreadSafe属性,所以,指定isTheadSafe为false后,在Tomcat 4.1.17中仍然出现多线程问题,这是Tomcat 4.1.17的Bug。在Tomcat 3.3.1和Resin 2.1.5中测试通过。
2. 去除实例变量,通过参数传递
从上面的分析可见,应该在Servlet/JSP中尽量避免使用实例变量。比如,下面的修正代码,去除了实例变量,通过定义局部变量,并参数进行传递。这样,由于局部变量是在线程的堆栈中进行分配的,所以是线程安全的。不会出现多线程同步的问题。代码如下:
<%@ page contentType="text/html;charset=GBK" %> <% //使用局部变量 String username; String password; java.io.PrintWriter output; //从request中获取参数 username = request.getParameter("username"); password = request.getParameter("password"); output = response.getWriter(); showUserInfo(output, username, password); %> <%! public void showUserInfo(java.io.PrintWriter _output, String _username, String _password) { //为了突出并发问题,在这儿首先执行一个费时操作 int i =0; double sum = 0.0; while (i++ < 200000000) { sum += i; } _output.println(Thread.currentThread().getName() + "<br>"); _output.println("username:" + _username + "<br>"); _output.println("password:" + _password + "<br>"); } %>
注:有的资料上指出在printUserInfo()方法或者实例变量的相关操作语句上使用synchronized关键字进行同步,但这样并不能解决多线程的问题。因为,这样虽然可以使对实例变量的操作代码进行同步,但并不能阻止一个线程使用另外一个线程修改后的“脏的”实例变量。所以,除了降低运行效率外,不会起到预期效果。
发表评论
-
java 线程池分析
2015-01-19 17:34 639转自 http://www.cnblogs.com/evilr ... -
JCA 综述
2011-08-25 15:01 1140什么是JCA?它最吸引人 ... -
web.xml 配置详解
2011-08-25 14:14 7071 定义头和根元素 部署描述符文件就像所有XML文件一样, ... -
xpath查询xml
2011-08-23 09:46 2064类似于使用SQL从数据库从查询数据。XPath可以方便的在XM ... -
自动登录
2011-08-17 14:42 1766一、什么是用户自动登录? 对于我们的网站向已注册用户提供 ... -
jad 安装
2011-08-11 14:47 1705Eclipse反编译工具Jad及插件JadClipse配置 ... -
LinkedHashMap 和 HashMap的区别
2011-08-11 10:13 936顾名思义LinkedHashMap是比HashMap多了一个链 ... -
cookie & session
2011-08-10 09:31 545二者的定义: 当你在浏览网站的时候,WEB 服务器会先送一小小 ... -
java异常处理之throw, throws,try和catch
2011-08-05 10:10 1384转载 http://blog.csdn.net/zhouyon ... -
Static Nested Class 和 Inner Class
2011-07-26 21:54 1110【转】Static Nested Class 和 Inner ... -
servlet 变量范围
2011-07-02 16:19 852如果要在整个应用范围可以用: request.getSessi ... -
tomcat outofmemoryerror permgen space java heap space
2011-06-28 15:07 1329windows 下 tomcat 虚拟内存 ... -
newInstance() 和 new 有什么区别?
2011-06-25 15:51 739在初始化一个类,生成一个实例的时候;newInstance() ... -
几种类加载方式的区别
2011-06-25 15:41 929虚拟机加载类的途径: 1、Dog dog = new Do ... -
运行时异常与一般异常
2011-06-25 15:39 1068Java提供了两类主要的异常:runtime exceptio ... -
ConcurrentHashMap实现原理
2011-06-25 15:14 1950ConcurrentHashMap是Java 5中 ... -
java集合
2011-06-25 15:00 777转载 当你事先不知道要存放数据的个数,或者你需要一种比数组下标 ... -
web.xml 中的listener、 filter、servlet 加载顺序及其详解
2011-06-25 14:21 811转载http://hi.baidu.com/suofang/b ... -
Servlet中listener和filter的总结
2011-06-25 14:04 1417转载 Listener我是这样理 ... -
final 关键字
2011-06-25 09:42 724Java中的final关键字通常 ...
相关推荐
Servlet/JSP 技术由于其多线程运行而具有很高的执行效率,但这也意味着需要非常细致地考虑多线程的安全性问题。 Servlet 的多线程机制是建立在 Java 多线程机制之上的。Servlet 容器会自动使用线程池等技术来支持...
- **高效**: 通过轻量级线程模型,Servlet可以快速响应新的请求,且不需要为每次请求都加载新的实例。 - **方便**: 内置了许多实用工具方法,如解析HTML表单数据、操作HTTP头、处理Cookie和管理会话状态等。 - **...
- 在多线程环境中,确保Servlet的线程安全非常重要。 - 通常采用同步机制(如`synchronized`关键字)、无状态设计等方式来保证线程安全。 ### 27. 中文问题(2) - 进一步讨论中文处理的问题,包括数据库连接、...
2. Servlet生命周期:初始化、服务、销毁三个阶段,以及Servlet配置和多线程处理。 3. 请求和响应对象的使用:如何从请求中获取参数,如何设置响应头和正文。 4. 数据库操作:使用JDBC连接数据库,执行SQL查询,处理...
- `isThreadSafe`:线程安全标志。 - `isELIgnored`:是否忽略表达式语言。 - `contentType`:设置内容类型。 - `pageEncoding`:设置页面编码。 例如: ```jsp *" session="true" %> ``` ##### 3.4 包含与...
然后,服务器将请求信息转发给Servlet,并为每个请求创建一个新的执行线程;Servlet处理请求,生成响应并返回给服务器,最后由服务器将响应送回客户端。 Servlet的生命周期包括三个阶段:初始化、执行和终止。初始...
- **并发问题**:在高并发环境下,确保多个线程同时访问Session时的安全性,可能需要采用同步机制或其他并发控制策略。 5. **性能优化**: - **避免过多Session数据**:减少Session中的数据量可以降低服务器内存...
- 异步处理能力,允许Servlet在处理请求时释放线程,提高并发性能。 11. **JSP 2.0新特性** - 更强大的EL表达式,支持方法调用和类型转换。 - 自动脚本元素,无需显式声明`和`%>`,提高JSP代码的可读性。 以上...
### servlet与Struts action线程安全问题分析 #### 一、引言 随着互联网应用的不断普及和发展,基于Servlet和JSP技术的应用程序在企业级应用中占据着重要的位置。Servlet作为一种常用的技术栈,因其多线程运行特性...
- **高效性:**Servlets使用线程而非操作系统进程,这意味着每个请求不会创建一个新的实例,而是由现有的Servlet实例处理,这极大地提高了效率。 - **便利性:**Servlets提供了大量的高级实用工具,如数据库访问、...
4. **多线程**:Servlet默认在一个线程中服务每个请求,因此需要考虑线程安全问题,特别是在共享数据时。 JSP(JavaServer Pages)是另一种Java Web技术,它允许开发者将HTML代码与Java代码混合编写,以生成动态...
- **高效性**:Servlet 在服务器端以 Java 线程的形式运行,相比于 CGI 每次请求都需要启动新的进程,Servlet 可以极大地减少进程启动带来的开销。此外,多个请求可以通过多个线程处理,而不需要多次加载相同的 ...
Servlet容器(如Tomcat、Jetty)负责管理Servlet实例,提供线程安全的环境,并自动处理客户端请求。 JSP是Servlet的另一种表现形式,它更注重视图层的开发,允许开发者使用HTML、CSS和Java脚本语言来编写页面。JSP...
在本书中,读者会学习到Servlet的生命周期、服务方法、多线程处理、Servlet配置以及Servlet容器的工作原理。此外,书中还会介绍如何使用Filter和Listener来增强应用程序的功能,比如日志记录、会话管理等。 在JSP与...
Servlet和JSP运行在Web容器(如Tomcat、Jetty等)中,这些容器提供了运行Java Web应用所需的环境,包括Servlet和JSP的生命周期管理、线程管理以及与HTTP协议的交互。 **总结** Servlet和JSP是Java Web开发的重要...
【标题】"javax.servlet3.0 javax.servlet_jsp2.0源码"涉及的是Java Servlet和JSP(JavaServer Pages)技术的核心API,这两个组件是Java Web开发的基础。源码分析可以帮助我们深入理解它们的工作原理。 【描述】...
- **多线程处理**:Servlet容器默认为每个请求分配独立的线程,理解如何正确处理线程安全问题对于提高应用性能至关重要。 通过以上知识点的介绍,《Servlet与JSP核心编程第二版》涵盖了Servlet和JSP技术的基本原理...
- **异步处理**:Servlet 3.0引入了异步处理的支持,使得Servlet能够处理长时间运行的任务而不会阻塞服务器线程。 #### 三、JSP技术详解 - **JSP基本语法**: - 脚本元素(Scriptlets):如`<% %>`用来执行Java...
本"jsp线程学习上课代码"的资源可能是为了教授如何在JSP中使用和管理线程,帮助开发者深入理解这一主题。源码的提供是为了让学生或初学者能够实际操作,从而更好地理解和学习。下面将详细探讨JSP与线程的相关知识点...