当前位置: 首页 > 图文教程 > 网络编程 > JSP > Servlet及JSP中的多线程同步问题

JSP
写一个对搜索引擎友好的文章SEO分页类
ajax+jsp草稿自动保存的实现代码
什么是eclipse,eclipse的意思解析
经常听朋友说什么J2EE,终于知道点什么是J2EE了,汗一个
搭建SSH时的思考和遇到的几个问题的解决方法
RMI使用学习 小结
weblogic 8.1下重新编译java类但不用重启服务器的方法
JSP下动态INCLUDE与静态INCLUDE的区别分析
jsp中文乱码 jsp mysql 乱码的解决方法
Jsp页面实现文件上传下载类代码
下载完成后页面不自动关闭的方法
XStream使用方法总结附实例代码
惊现支撑1亿pv/天的超级数据库解决方案
jsp遍历文件夹下的文件的代码
JSP中include指令和include行为的区别
FCKeditor使用方法(FCKeditor_2.6.3)详细使用说明
AJAX FCKEditor Rich Editor整合篇
Java下使用Oracle存储过程(详解)
java AJAX实现级联下拉框
java去掉html标签 必须首先去掉双引号的正则

Servlet及JSP中的多线程同步问题


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-11-02   浏览: 59 ::
收藏到网摘: n/a

    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两个线程的时间线


  而实际程序中,由于设置实例变量,使用实例变量这两个时间点非常接近,所以,像本例的同步问题并没有这么突出,可能会偶尔出现,但这却更加