`
androidssh
  • 浏览: 115224 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Servlet和JSP的线程安全问题

阅读更多
   编写Servlet和JSP的时候,线程安全问题很容易被忽略,如果忽视了这个问题,你的程序就存在潜在的隐患.
一、Servlet的线程安全简介
1、Servlet的生命周期
    Servlet的生命周期是由Web容器负责的,当客户端第一次请求Servlet时,容器负责初始化Servlet,也就是实例化这个Servlet类.以后这个实例就负责客户端的请求,一般不会再实例化其他Servlet类,也就是有多个线程在使用这个实例.Servlet之所以比CGI效率高就是因为Servlet是多线程的.如果该Servlet被声明为单线程模型的话,容器就会维护一个实例池,那么将存在多个实例.
2、Java的内存模型JMM(Java Memory Model)
    JMM主要是为了规定了线程和内存之间的一些关系。根据JMM的设计,系统存在一个主内存(Main Memory),Java中所有实例变量都储存在主存中,对于所有线程都是共享的。每条线程都有自己的工作内存(Working Memory),工作内存由缓存和堆栈两部分组成,缓存中保存的是主存中变量的拷贝,缓存可能并不总和主存同步,也就是缓存中变量的修改可能没有立刻写到主存中;堆栈中保存的是线程的局部变量(save in stack, not in heap),线程之间无法相互直接访问堆栈中的变量.

3、Servlet的线程安全
    Servlet规范已经声明Servlet不是线程安全的,所以在开发Servlet的时候要注要这个问题.这里以一个现实的模型来说明问题,先定义一个Servlet类,再定义一个SmulateMultiThread类和WebContainer类.
import javax.servlet.http.HttpServlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

//该类模拟多线程Servlet的情况
public class SmulateMultiThread implements Runnable{
  public SmulateMultiThread() {
  }
  public static void main(String[] args) {
   //处理100个请求
    for(int i=0;i<100;i++)
    {
      new Thread(new SmulateMultiThread()).start();
    }
  }
  public void run()  {
    HttpServletRequest request=null;
    HttpServletResponse  response=null;
    try {
      WebContainer.getServlet().doGet(request, response);
    }
    catch (IOException ex) {
    }
    catch (ServletException ex) {
    }
  }
}
//这是一个Servlet类
class UnsafeServlet extends HttpServlet{
  private String unsafe;
  public void init() throws ServletException {
  }
  //Process the HTTP Get request
  public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    unsafe=Thread.currentThread().getName();
    System.out.println(unsafe);
  }
}
//这个是容器类
class WebContainer{
  private static UnsafeServlet us=new UnsafeServlet();
  public static UnsafeServlet getServlet(){
    return us;
  }
}
    输出了100不同的线程名称,如果有100个请求同时被这个Servlet处理的话,那么unsafe就可能有100种去值,最后客户端将得到错误的值.比如客户1请求的线程名为thread-1,但是返回给他的可能是thread-20.表现在现实中就是,我登陆的用户名是user1,登陆后变成了user2.
    那么怎样才能是Servlet安全呢,凡是多个线程可以共享的就不要使用(实例变量+类变量),就这么简单.也可以使用synchronized同步方法,但是这样效率不高,还可以使用单线程模型,这样的话效率就更低了,100个请求同时来的时候就要实例化100个实例.
方法中的临时变量是不会影响线程安全的,因为他们是在栈上分配空间,而且每个线程都有自己私有的栈空间.

二、Servelt安全线程设计方法
    通过上面的分析,我们知道了实例变量不正确的使用是造成Servlet线程不安全的主要原因。下面针对该问题给出了三种解决方案并对方案的选取给出了一些参考性的建议。
1、实现 SingleThreadModel 接口
  该接口指定了系统如何处理对同一个Servlet的调用。如果一个Servlet被这个接口指定,那么在这个Servlet中的service方法将不会有两个线程被同时执行,当然也就不存在线程安全的问题。这种方法只要将前面的UnsafeServlet类的类头定义更改为:
public class UnsafeServlet  extends HttpServlet implements SingleThreadModel {
…………
}
2、同步对共享数据的操作
  使用synchronized 关键字能保证一次只有一个线程可以访问被保护的区段,在本论文中的Servlet可以通过同步块操作来保证线程的安全。同步后的代码如下:
…………
Public class UnsafeServlet  extends HttpServlet {
     …………
username = request.getParameter ("username");
synchronized (this){
output = response.getWriter ();
try {
     Thread. Sleep (5000);
} Catch (Interrupted Exception e){}
     output.println("用户名:"+Username+"
");
    }
  }
}
3、避免使用实例变量
  本实例中的线程安全问题是由实例变量造成的,只要在Servlet里面的任何方法里面都不使用实例变量,那么该Servlet就是线程安全的。
  修正上面的Servlet代码,将实例变量改为局部变量实现同样的功能,代码如下:
……
public class UnsafeServlet   extends HttpServlet {
     public void service (HttpServletRequest request,
             HttpServletResponse response) throws ServletException, IOException {
         PrintWriter output;
         String username;
         response.setContentType ("text/html; charset=gb2312");
         ……
     }
}
  对上面的三种方法进行测试,可以表明用它们都能设计出线程安全的Servlet程序。但是,如果一个Servlet实现了 SingleThreadModel接口,Servlet引擎将为每个新的请求创建一个单独的Servlet实例,这将引起大量的系统开销。 SingleThreadModel在Servlet2.4中已不再提倡使用;同样如果在程序中使用同步来保护要使用的共享的数据,也会使系统的性能大大下降。这是因为被同步的代码块在同一时刻只能有一个线程执行它,使得其同时处理客户请求的吞吐量降低,而且很多客户处于阻塞状态。另外为保证主存内容和线程的工作内存中的数据的一致性,要频繁地刷新缓存,这也会大大地影响系统的性能。所以在实际的开发中也应避免或最小化 Servlet 中的同步代码;在Serlet中避免使用实例变量是保证Servlet线程安全的最佳选择。从Java 内存模型也可以知道,方法中的临时变量是在栈上分配空间,而且每个线程都有自己私有的栈空间,所以它们不会影响线程的安全。
  小结
  Servlet的线程安全问题只有在大量的并发访问时才会显现出来,并且很难发现,因此在编写Servlet程序时要特别注意。线程安全问题主要是由实例变量造成的,因此在Servlet中应避免使用实例变量。如果应用程序设计无法避免使用实例变量,那么使用同步来保护要使用的实例变量,但为保证系统的最佳性能,应该同步可用性最小的代码路径。

三、JSP中线程安全
JSP的本质是Servlet,所有只要明白了Servlet的安全问题,JSP的安全问题应该很容易理解.使用<%! %>声明的变量是Servlet的实例变量,不是线程安全的,其他都是线程安全的.
<%! String unsafeVar; %> //不是线程安全的
<% String safeVar; %>      // 线程安全的

    总结:线程安全问题主要是由实例变量造成的,不管在Servlet还是JSP,或者在Struts的Action里面,不要使用实例变量,任何方法里面都不要出现实例变量,你的程序就是线程安全的.

分享到:
评论

相关推荐

    servlet线程安全问题

    同时,需要了解 Servlet 的多线程机制和线程安全问题的解决方法,以确保编写的程序是安全、可靠的。 在 Servlet 中,实例变量的使用需要非常小心,因为实例变量可能会被多个线程同时访问。如果不注意实例变量的使用...

    servlet与Struts action线程安全问题分析(pdf)

    针对Servlet和Struts中的线程安全问题,有几种常见的解决策略: 1. **避免使用实例变量**:尽可能减少实例变量的使用,将它们改为局部变量或使用静态变量。 2. **同步实例变量**:如果必须使用实例变量,可以通过...

    Servlet和JSP学习指南.pdf

    4. **多线程**:Servlet默认在一个线程中服务每个请求,因此需要考虑线程安全问题,特别是在共享数据时。 JSP(JavaServer Pages)是另一种Java Web技术,它允许开发者将HTML代码与Java代码混合编写,以生成动态...

    Servlet与JSP之间的关系

    Servlet和JSP是Java Web开发中的两种核心技术,它们在Web应用程序中扮演着不同的角色,但密切相关,共同构建了动态Web内容的生成。 Servlet是一个位于Web服务器内部的Java应用程序,能够生成动态的Web内容。Servlet...

    Java+Servlet和JSP教程

    此外,多个请求可以通过多个线程处理,而不需要多次加载相同的 Servlet 类,这大大提高了系统的响应速度和吞吐量。 - **便捷性**:Servlet 提供了一套丰富的 API 和工具方法,如自动解析 HTML 表单数据、读取和设置...

    Servlet+JSP购物车

    - **并发问题**:在高并发环境下,确保多个线程同时访问Session时的安全性,可能需要采用同步机制或其他并发控制策略。 5. **性能优化**: - **避免过多Session数据**:减少Session中的数据量可以降低服务器内存...

    韩顺平servlet和jsp课堂笔记

    6. **多线程**:每个请求都会创建一个新的Servlet实例,因此Servlet天生支持多线程,需要注意同步问题以避免数据竞争。 【JSP知识点】: 1. **JSP简介**:JSP是一种动态网页技术,将HTML、CSS、JavaScript与Java...

    Servlet与JSP核心编程(第2卷 第2版)

    Servlet和JSP(JavaServer Pages)是Java Web开发中的核心技术,用于构建动态、交互式的Web应用程序。《Servlet与JSP核心编程(第2卷 第2版)》这本书深入讲解了这两项技术,帮助开发者理解并掌握其核心概念、用法以及...

    Tomcat开发JSP和Servlet需要注意的问题.doc

    在使用Tomcat开发JSP和Servlet时,需要注意一些关键点以确保程序的正确运行和优化。以下是根据提供的文件内容整理的一些重要问题和解决方案: 1. **创建Tomcat项目**: - 在Eclipse等集成开发环境中,需要创建一个...

    Servlet+Jsp+技术概述

    Servlet和JSP运行在Web容器(如Tomcat、Jetty等)中,这些容器提供了运行Java Web应用所需的环境,包括Servlet和JSP的生命周期管理、线程管理以及与HTTP协议的交互。 **总结** Servlet和JSP是Java Web开发的重要...

    javax.servlet3.0 javax.servlet_jsp2.0源码

    【标题】"javax.servlet3.0 javax.servlet_jsp2.0源码"涉及的是Java Servlet和JSP(JavaServer Pages)技术的核心API,这两个组件是Java Web开发的基础。源码分析可以帮助我们深入理解它们的工作原理。 【描述】...

    java web教程(servlet,jsp,jdbc)java高手真经

    Servlet容器(如Tomcat、Jetty)负责管理Servlet实例,提供线程安全的环境,并自动处理客户端请求。 JSP是Servlet的另一种表现形式,它更注重视图层的开发,允许开发者使用HTML、CSS和Java脚本语言来编写页面。JSP...

    JavaServlet和JSP教程

    3. **线程安全性**:每个请求都会在一个单独的线程中处理,因此Servlet必须确保线程安全。 #### 四、JSP简介 JSP(Java Server Pages)是由Sun Microsystems开发的一种技术,用于简化Servlet的开发过程。JSP允许...

    吉林大学珠海学院JSP&Servlet学习笔记(第二版)课后答案

    本笔记共分为九章,每章节都包含了相关的问题答案,涉及到JSP和Servlet的各个方面。 在第一章中,本笔记涵盖了JSP的基本概念,包括JSP的历史发展、JSP的特点、JSP的基本结构等。同时,本章节还介绍了JSP的生命周期...

    JSP和Servlet

    4. 静态类:静态类不需要实例化即可使用,但其成员变量可能存在线程安全问题,需要额外的同步机制。 5. 外部资源:比如文件、数据库连接等,如果多个线程或进程同时操作,需要确保适当的同步措施。 以下是一个示例...

    jsp&servlet电子书

    在学习JSP与Servlet的过程中,学生常常会遇到各种问题,例如概念混淆、操作难度、应用场景的理解以及相关认证考试的准备等,这本书都进行了详尽的解答和深入的探讨。 JSP(Java Server Pages)是Java平台上的动态...

    servlet和jsp学习笔记

    Servlet和JSP是Java Web开发中的核心技术,它们用于构建动态网页和服务器端应用程序。这篇学习笔记将深入探讨这两个概念,以及它们在实际开发中的应用。 Servlet是Java编程语言的一个接口,由Sun Microsystems(现...

    美河图书提供.Servlet与JSP核心编程第二版_带目录

    - **多线程处理**:Servlet容器默认为每个请求分配独立的线程,理解如何正确处理线程安全问题对于提高应用性能至关重要。 通过以上知识点的介绍,《Servlet与JSP核心编程第二版》涵盖了Servlet和JSP技术的基本原理...

Global site tag (gtag.js) - Google Analytics