- 浏览: 283749 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (204)
- Ubuntu (8)
- Maven (1)
- JVM (12)
- Shell (11)
- WEB (24)
- 数据库 (1)
- Linux (24)
- ibatis源码 (8)
- 乱七八糟 (6)
- memcache (2)
- 数据结构 (1)
- mongoDb (3)
- WebService (1)
- 装机 (1)
- zookeeper (0)
- Hbase (4)
- mysql (6)
- nginx (3)
- SSDB (0)
- kafka消息 (3)
- Rust语言学习 (2)
- Tair学习 (0)
- ES (7)
- freeMarker (2)
- 分布式任务调度学习 (0)
- Apache Camel翻译 (1)
- Storm (1)
- Netty (3)
- NodeJs (1)
- BootStrap (1)
- 读书计划 (0)
- databus (1)
- Socket编程 (1)
- Redis (5)
- Hystrix (2)
- JDK (2)
- JMeter测试 (1)
- Idea (8)
- JProfile学习 (9)
- springBoot (6)
- httpClient (1)
- Docker学习 (1)
- 微信小程序学习 (1)
- beanstalkd (0)
- gradle (1)
- 硬盘学习 (0)
- activiti-engine (1)
- 算法 (3)
- thrfit学习 (1)
- serviceMesh (2)
- 流控 (0)
- TCP (0)
最新评论
-
k_kid9157:
亲测可用 特来感谢LZ分享!
the namespace on the "definitions" element, is not atorChain doIntercept Interce -
fair_jm:
归纳得很好 还有G1 学习了
java的垃圾收集算法和垃圾收集器 -
zhouchaofei2010:
有理想 赞一个
ibatis源码 -
code_cj:
好像在哪里看过,有点熟眼...
jvm如何判断对象已死? -
ansjsun:
不错不错..就是有点粗略..希望能介绍下.标记整理和标记删除. ...
jvm如何判断对象已死?
Servlet/JSP技术和ASP、PHP等相比,由于其多线程运行而具有很高的执行效率。由于Servlet/JSP默认是以多线程模式执行的,所以,在编写代码时需要非常细致地考虑多线程的同步问题。然而,很多人编写Servlet/JSP程序时并没有注意到多线程同步的问题,这往往造成编写的程序在少量用户访问时没有任何问题,而在并发用户上升到一定值时,就会经常出现一些莫明其妙的问题,对于这类随机性的问题调试难度也很大。
一、在Servlet/JSP中的几种变量类型
在编写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中,通过设置:,在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关键字进行同步,但这样并不能解决多线程的问题。因为,这样虽然可以使对实例变量的操作代码进行同步,但并不能阻止一个线程使用另外一个线程修改后的“脏的”实例变量。所以,除了降低运行效率外,不会起到预期效果。
摘自:http://www.neu.edu.cn/network/show.php?id=35
一、在Servlet/JSP中的几种变量类型
在编写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中,通过设置:,在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关键字进行同步,但这样并不能解决多线程的问题。因为,这样虽然可以使对实例变量的操作代码进行同步,但并不能阻止一个线程使用另外一个线程修改后的“脏的”实例变量。所以,除了降低运行效率外,不会起到预期效果。
摘自:http://www.neu.edu.cn/network/show.php?id=35
发表评论
-
四层、七层负载均衡的区别(转)
2019-04-18 03:06 418简介 区别 Nginx、LVS及HAP ... -
OSI七层协议图解(转)
2019-04-18 02:38 568图解 转自: https://www.cnblogs.co ... -
AES加密时抛出java.security.InvalidKeyException: Illegal key size or default parameter
2017-08-22 11:50 646使用AES加密时,当密钥大于128时,代码会抛出java.s ... -
springMVC支持jsonp
2017-06-29 14:39 617@RequestMapping("directive ... -
Spring Batch学习
2017-02-14 16:17 709https://www.ibm.com/developerwo ... -
guava缓存
2016-09-18 09:57 487http://outofmemory.cn/java/guav ... -
java毫秒和微秒区别
2016-08-02 09:59 0http://blog.csdn.net/dliyuedong ... -
gcc查看当前的版本并升级
2016-03-19 18:45 34441.gcc查看版本:gcc -v MacBook-Pro:$ ... -
java发送邮件附件乱码的解决
2016-03-17 13:17 943import javax.mail.internet.Mime ... -
Error finishing response
2015-02-13 19:02 1174https://issues.apache.org/bugzi ... -
Missing artifact com.sun:tools:jar:1.5.0
2015-01-28 14:30 756当导入maven项目时出现: Missing artifac ... -
velocity1.6.3导致cpu过高
2014-09-06 22:00 794velocity1.6.3的bug导致cpu过大。 https ... -
doc 编码 GBK 的不可映射字符
2014-03-31 20:16 862如果提示:编码 GBK 的不可映射字符 eclipse 生成 ... -
Cannot find the declaration of element 'beans'. 的解决方法
2013-12-05 09:47 2404org.xml.sax.SAXParseException: ... -
Tomcat日志处理(包括catalina.out切分)
2013-11-07 09:57 20281 Tomcat 日志信息分为两类 : 一是运行中的日志,它 ... -
TortoiseSVN更改账号的方法 (转)
2013-10-14 13:46 1178在copy其它用户check的项目到本地后,把账号信息也带过 ... -
tomcat下域名的配置,ROOT.xml的作用
2012-12-13 11:36 1776以下小结使用tomcat5.0.28测试通过,tomcat安装 ... -
在布署Tomcat时,出现The scratchDir you specified is unusable
2012-12-10 12:53 7845布署Tomcat报错 ....... 2007-12-22 ... -
tomcat报BAD packet signature 18245错误的原因
2012-12-03 10:14 2068最近把项目部署到windows服务器上面,通过tomcat跑 ... -
validateJarFile jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending
2012-12-01 10:02 1047把那个 jsp-api.jar servlet-api.jar ...
相关推荐
- **并发问题**:在高并发环境下,确保多个线程同时访问Session时的安全性,可能需要采用同步机制或其他并发控制策略。 5. **性能优化**: - **避免过多Session数据**:减少Session中的数据量可以降低服务器内存...
在Java Web开发中,Tomcat是一个广泛...综上所述,理解Tomcat中的多线程处理对于优化Servlet性能和解决潜在的并发问题至关重要。通过对线程池的配置和使用最佳实践,开发者可以有效地提高Web应用的响应速度和可伸缩性。
6. **多线程**:每个请求都会创建一个新的Servlet实例,因此Servlet天生支持多线程,需要注意同步问题以避免数据竞争。 【JSP知识点】: 1. **JSP简介**:JSP是一种动态网页技术,将HTML、CSS、JavaScript与Java...
随着互联网应用的不断普及和发展,基于Servlet和JSP技术的应用程序在企业级应用中占据着重要的位置。Servlet作为一种常用的技术栈,因其多线程运行特性而具备较高的执行效率。然而,这种多线程特性同时也带来了一定...
为了保证多线程环境下的正确运行,应避免在Servlet类中使用实例变量,因为这些变量会被多个线程共享,可能导致数据不一致。相反,使用局部变量是推荐的做法,因为它们在每个线程的栈中独立存在,不会引起共享问题。 ...
线程安全就是多线程操作同一个对象不会有问题,线程同步一般来保护线程安全, 所以可以在Servlet的线程里面加上同步方法或同步块。 (Synchronized)可以保证在同一时间只有一个线程访问,(使用同步块会导致性能...
8. **线程安全的Java集合**:在多线程环境中,使用线程安全的集合类(如`ConcurrentHashMap`、`Vector`)可以避免并发问题。 9. **JSP内置对象与线程安全**:JSP的内置对象(如`session`, `request`, `response`)...
Java是企业级应用开发的...这些面试题涵盖了Java基础、集合框架、多线程、网络编程、Servlet和JSP等多个核心领域,全面展示了开发者应该具备的技能和知识。理解和掌握这些内容对于成为一名优秀的Java开发人员至关重要。
由于Servlet本质是多线程的,因此JSP天生支持多线程操作。在处理并发请求时,JSP和其背后的Servlet容器(如Tomcat)会利用多线程来提高性能。 2. **Servlet**:Servlet是Java编写的小型服务器端程序,用于扩展...
一个Servlet实例可能为多个请求服务,因此开发者必须注意线程安全问题。如果Servlet内部有成员变量,它们应被声明为线程安全的或者在每个请求处理中进行适当的同步。 6. **转发与重定向**: - **转发**(Forward...
3. Example2_2.jsp:此页面引入了synchronized关键字,展示了在多线程环境中如何安全地更新计数器。在Servlet容器中,每个JSP页面都会被转换为一个Servlet类,因此多个用户并发访问时,同步方法确保了对number变量的...
- 在多线程环境中,确保Servlet的线程安全非常重要。 - 通常采用同步机制(如`synchronized`关键字)、无状态设计等方式来保证线程安全。 ### 27. 中文问题(2) - 进一步讨论中文处理的问题,包括数据库连接、...
4. **多线程**:线程的基本概念、线程的生命周期、线程的创建方式(实现Runnable接口、继承Thread类)、线程同步与锁机制。 #### JSP与Servlet技术详解 1. **JSP概述**:JSP(JavaServer Pages)是一种基于Java的...
5. **JSP中的多线程**:在Java Server Pages(JSP)中,虽然JSP本身不是多线程的,但它们运行在Servlet容器中,而Servlets是多线程的。每个HTTP请求都会在单独的线程中处理,因此理解如何在Servlet中正确地管理线程...
在IT行业中,多线程和图片下载是两个关键的技术领域,尤其在Web开发中,如JSP(JavaServer Pages)应用程序。"多线程双图片源下载jsp"这个实例展示了如何利用多线程技术从Google和Flickr这两个知名的图片服务平台上...
5. 线程同步的方法有wait()、sleep()、notify()、notifyAll()等。 6. 多线程有两种实现方法,分别是继承Thread类与实现Runnable接口。同步的实现方面有两种,分别是synchronized和wait与notify。 7. 线程的基本概念...
在实际开发过程中,还需要考虑安全性、并发控制、错误处理、性能优化等多方面的问题。例如,使用HTTPS确保数据传输的安全,使用线程安全的数据结构处理并发请求,以及使用缓存技术提高响应速度。同时,设计良好的...
- **线程安全性**:虽然JSP引擎处理了大部分多线程的问题,但在开发过程中仍然需要注意线程安全问题。例如,避免在Servlet中使用非线程安全的数据结构,确保共享资源的正确同步等。 **2.2 持久性** - **持久性**:...