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

开发
本文描述Servlet和JSP中的多线程同步问题,以及问题的解决方案,还介绍了在Servlet和JSP中的几种变量类型。

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中,使用实例变量要特别谨慎。首先请看下面的代码:

  1. // instanceconcurrenttest.jsp  
  2. <%@ page contentType="text/html;charset=GBK" %> 
  3. <%!  
  4. //定义实例变量  
  5. String username;  
  6. String password;  
  7. java.io.PrintWriter output;  
  8. %> 
  9. <%  
  10. //从request中获取参数  
  11. username = request.getParameter("username");  
  12. password = request.getParameter("password");  
  13. output = response.getWriter();  
  14. showUserInfo();  
  15. %> 
  16. <%!  
  17. public void showUserInfo() {  
  18. //为了突出并发问题,在这儿首先执行一个费时操作  
  19. int i =0;  
  20. double sum = 0.0;  
  21. while (i++ < 200000000) {  
  22. sum += i;  
  23. }  
  24. output.println(Thread.currentThread().getName() + "<br>");  
  25. output.println("username:" + username + "<br>");  
  26. output.println("password:" + password + "<br>");  
  27. }  
  28. %> 

在这个页面中,首先定义了两个实例变量,username和password。然后在从request中获取这两个参数,并调用 showUserInfo()方法将请求用户的信息回显在该客户的浏览器上。在一个用户访问是,不存在问题。但在多个用户并发访问时,就会出现其它用户的信息显示在另外一些用户的浏览器上的问题。这是一个严重的问题。为了突出并发问题,便于测试、观察,我们在回显用户信息时执行了一个模拟的费时操作,比如,下面的两个用户同时访问(可以启动两个IE浏览器,或者在两台机器上同时访问):
◆http://localhost:8080/instanceconcurrenttest.jsp?username=a&password=123
◆http://localhost:8080/instanceconcurrenttest.jsp?username=b&password=456

  1. // InstanceConcurrentTest.java  
  2. import javax.servlet.*;  
  3. import javax.servlet.http.*;  
  4. import java.io.PrintWriter;  
  5. public class InstanceConcurrentTest extends HttpServlet  
  6. {  
  7. String username;  
  8. String password;  
  9. PrintWriter out;  
  10. public void doGet(HttpServletRequest request,  
  11. HttpServletResponse response)  
  12. throws ServletException,java.io.IOException  
  13. {  
  14. //从request中获取参数  
  15. username = request.getParameter("username");  
  16. password = request.getParameter("password");  
  17. System.out.println(Thread.currentThread().getName() +  
  18. " | set username:" + username);  
  19. out = response.getWriter();  
  20. showUserInfo();  
  21. }  
  22. public void showUserInfo() {  
  23. //为了突出并发问题,在这儿首先执行一个费时操作  
  24. int i =0;  
  25. double sum = 0.0;  
  26. while (i++ < 200000000) {  
  27. sum += i;  
  28. }  
  29. out.println("thread:" + Thread.currentThread().getName());  
  30. out.println("username:"+ username);  
  31. out.println("password:" + password);  
  32. }  

 

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中尽量避免使用实例变量。比如,下面的修正代码,去除了实例变量,通过定义局部变量,并参数进行传递。这样,由于局部变量是在线程的堆栈中进行分配的,所以是线程安全的。不会出现多线程同步的问题。代码如下:

【编辑推荐】

  1. 无需修改代码增强Servlet和JSP的安全性
  2. 详解JSP指令和脚本元素
  3. 如何加快JSP访问速度
  4. 谈JSP与XML的交互
  5. Tomcat下JSP、Servlet和Bean的配置
责任编辑:佚名 来源: IT168
相关推荐

2009-07-03 17:18:34

Servlet多线程

2009-07-07 13:29:33

Servlet和JSP

2009-07-03 16:53:11

Servlet容器

2009-08-10 09:19:28

Servlet JSP

2009-07-03 14:02:51

2011-06-22 13:57:54

Java多线程

2011-06-22 13:47:16

Java多线程

2009-06-25 14:26:07

JSPJavaBeanServlet

2009-07-06 09:49:26

Servlet JSP

2009-07-06 15:34:56

JSP和Servlet

2019-07-31 09:06:35

Java跳槽那些事儿文章

2009-03-24 08:56:23

数据同步多线程Java

2009-07-08 09:22:03

Servlet和JSP

2009-06-30 15:37:27

Servlet和JSP

2010-01-21 11:27:30

linux多线程机制线程同步

2012-06-05 02:12:55

Java多线程

2009-03-02 09:45:45

2009-07-07 13:42:57

Servlet JSP

2009-07-09 10:49:56

Servlet和JSP

2015-07-22 09:39:38

IOS多线程同步
点赞
收藏

51CTO技术栈公众号