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() + "
 
");- output.println("username:" + username + "
 
");- output.println("password:" + password + "
 
");- }
 - %>
 
在这个页面中,首先定义了两个实例变量,username和password。然后在从request中获取这两个参数,并调用 showUserInfo()方法将请求用户的信息回显在该客户的浏览器上。在一个用户访问是,不存在问题。但在多个用户并发访问时,就会出现其它用户的信息显示在另外一些用户的浏览器上的问题。这是一个严重的问题。为了突出并发问题,便于测试、观察,我们在回显用户信息时执行了一个模拟的费时操作,比如,下面的两个用户同时访问(可以启动两个IE浏览器,或者在两台机器上同时访问):
◆http://localhost:8080/instanceconcurrenttest.jsp?username=a&password=123
◆http://localhost:8080/instanceconcurrenttest.jsp?username=b&password=456
- // 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
三、解决方案
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中尽量避免使用实例变量。比如,下面的修正代码,去除了实例变量,通过定义局部变量,并参数进行传递。这样,由于局部变量是在线程的堆栈中进行分配的,所以是线程安全的。不会出现多线程同步的问题。代码如下:
【编辑推荐】
                分享文章:Servlet和JSP中的多线程同步问题
                
                网页地址:http://www.csdahua.cn/qtweb/news34/208234.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网