聊聊Servlet、Struts1、Struts2以及SpringMvc中的线程安全

转载 2018年04月16日 10:59:09

前言

很多初学者,甚至是工作1-3年的小伙伴们都可能弄不明白?servlet Struts1 Struts2 springmvc 哪些是单例,哪些是多例,哪些是线程安全?

在谈这个话题之前,我们先了解一下Java中相关的变量类型以及内存模型JMM。

变量类型

  • 类变量:独立于方法之外的变量,用 static 修饰。
  • 局部变量:类的方法中的变量。
  • 实例变量(全局变量):独立于方法之外的变量,不过没有 static 修饰。

JAVA的局部变量

  • 局部变量声明在方法、构造方法或者语句块中;
  • 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁;
  • 访问修饰符不能用于局部变量;
  • 局部变量只在声明它的方法、构造方法或者语句块中可见;
  • 局部变量是在栈上分配的。
  • 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。

JAVA的实例变量

  • 实例变量声明在一个类中,但在方法、构造方法和语句块之外;
  • 当一个对象被实例化之后,每个实例变量的值就跟着确定;
  • 实例变量在对象创建的时候创建,在对象被销毁的时候销毁;
  • 实例变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息;
  • 实例变量可以声明在使用前或者使用后;
  • 访问修饰符可以修饰实例变量;
  • 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见;
  • 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObejectReference.VariableName。

JAVA的类变量(静态变量)

  • 类变量也称为静态变量,在类中以static关键字声明,但必须在方法构造方法和语句块之外。
  • 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。
  • 静态变量除了被声明为常量外很少使用。常量是指声明为public/private,final和static类型的变量。常量初始化后不可改变。
  • 静态变量储存在静态存储区。经常被声明为常量,很少单独使用static声明变量。
  • 静态变量在程序开始时创建,在程序结束时销毁。
  • 与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为public类型。
  • 默认值和实例变量相似。数值型变量默认值是0,布尔型默认值是false,引用类型默认值是null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。
  • 静态变量可以通过:ClassName.VariableName的方式访问。
  • 类变量被声明为public static final类型时,类变量名称一般建议使用大写字母。如果静态变量不是public和final类型,其命名方式与实例变量以及局部变量的命名方式一致。

Java的内存模型JMM

Java的内存模型JMM(Java Memory Model)JMM主要是为了规定了线程和内存之间的一些关系。根据JMM的设计,系统存在一个主内存(Main Memory),Java中所有实例变量都储存在主存中,对于所有线程都是共享的。每条线程都有自己的工作内存(Working Memory),工作内存由缓存和堆栈两部分组成,缓存中保存的是主存中变量的拷贝,缓存可能并不总和主存同步,也就是缓存中变量的修改可能没有立刻写到主存中;堆栈中保存的是线程的局部变量,线程之间无法相互直接访问堆栈中的变量。根据JMM,我们可以将论文中所讨论的Servlet实例的内存模型抽象为下图所示的模型。

线程安全

Servlet

Servlet/JSP技术和ASP、PHP等相比,由于其多线程运行而具有很高的执行效率。由于Servlet/JSP默认是以多线程模式执行的,所以,在编写代码时需要非常细致地考虑多线程的安全性问题。然而,很多人编写Servlet/JSP程序时并没有注意到多线程安全性的问题,这往往造成编写的程序在少量用户访问时没有任何问题,而在并发用户上升到一定值时,就会经常出现一些莫明其妙的问题。

Servlet的多线程机制

Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的。当客户端第一次请求某个Servlet 时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类。当有新的客户端请求该Servlet时,一般不会再实例化该 Servlet类,也就是有多个线程在使用这个实例。Servlet容器会自动使用线程池等技术来支持系统的运行,如下图所示。

这样,当两个或多个线程同时访问同一个Servlet时,可能会发生多个线程同时访问同一资源的情况,数据可能会变得不一致。所以在用Servlet构建的Web应用时如果不注意线程安全的问题,会使所写的Servlet程序有难以发现的错误。

Servlet的线程安全问题

Servlet的线程安全问题主要是由于实例变量使用不当而引起的,这里以一个现实的例子来说明。

/**
 * 模拟用户AB在同时执行不同的动作
 * 先执行 http://localhost:8080/concurrent?username=A&action=play
 * 稍后执行 http://localhost:8080/concurrent?username=B&action=eat
 */
public class Concurrent extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private String action = "";//动作  
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {  
            String username = request.getParameter("username");  
            action = request.getParameter("username");  
            Thread.sleep(5000); //为了突出并发问题,在这设置一个延时  
            //如果不出意外,应该用户AB都在吃饭
            System.out.println("用户:"+username+"在"+action);
        } catch (Exception e) {  
        }  
    }
}

Struts1

首先,明确一点Sturts1 action是单例模式,线程是不安全的。Struts1使用的ActionServlet是单例的,既然是单例,当使用实例变量的时候就会有线程安全的问题。所有一般在开发中试禁止使用实例变量的。

Struts2

struts2使用的是actionContext,都是使用里面的实例变量,让struts2自动匹配成对象的。每次处理一个请求,struts2就会实例化一个对象,这样就不会有线程安全的问题了。

需要注意的是,如果struts2+spring来管理注入的时候,不要把Action设置成单例,否则会出问题的。当然现在很少有项目使用struts2了。

SpringMVC

SpringMVC的controller默认是单例模式的,所以也会有多线程并发的问题。

总结

  • servlet Struts1 SpringMvc 是线程不安全的,当然如果你不使用实例变量也就不存在线程安全的问题了。

  • Struts2 是线程安全的,当然前提情况是,Action 不交给 spring管理,并且不设置为单例。

  • SpringMvc 的 Bean 可以设置成多例变成线程安全,但是一定程度上回影响系统性能。

http://www.wrq6652.cn/
http://www.oph4016.cn/
http://www.eis6490.cn/
http://www.xfq2422.cn/
http://www.tlj5370.cn/
http://www.pqi7094.cn/
http://www.wky2337.cn/
http://www.veo5593.cn/
http://www.lpn9733.cn/
http://www.hxp7546.cn/
http://www.uht8250.cn/
http://www.erg7887.cn/
http://www.zrg4662.cn/
http://www.gmw7502.cn/
http://www.omk7549.cn/
http://www.cck2829.cn/
http://www.ujn9355.cn/
http://www.mgj9519.cn/
http://www.rig2765.cn/
http://www.irw9322.cn/
http://www.psd6888.cn/
http://www.pnl2718.cn/
http://www.com0678.cn/
http://www.oku7898.cn/
http://www.tas9765.cn/
http://www.vgz0064.cn/
http://www.nld6227.cn/
http://www.hco5930.cn/
http://www.oqs1669.cn/
http://www.nny5237.cn/
http://www.tyc6381.cn/
http://www.qmi0117.cn/
http://www.ylz8420.cn/
http://www.vha4867.cn/
http://www.frm7103.cn/
http://www.alo1362.cn/
http://www.phv0172.cn/
http://www.ppb5307.cn/
http://www.nzx0496.cn/
http://www.kwb7023.cn/
http://www.jyr2443.cn/
http://www.dbz8514.cn/
http://www.cok3166.cn/
http://www.rws5532.cn/
http://www.buw8082.cn/
http://www.hce3357.cn/
http://www.pjv6550.cn/
http://www.wlc0063.cn/
http://www.pqp2736.cn/
http://www.apv1822.cn/
http://www.tqr5934.cn/
http://www.goa7029.cn/
http://www.ldt5599.cn/
http://www.kcs8048.cn/
http://www.xyj1895.cn/
http://www.jbk1285.cn/
http://www.oka9409.cn/
http://www.wvc5486.cn/

Struts1,2,Servlet,Spring MVC单例多例 线程安全

Struts 1单例,线程不安全,在请求的时候被第一次初始化 action中的service对象为何不会出现数据存储的错误,大体意思就是每一个用户发出一次请求后就有一个独立的线程与之绑定,且有一个对...
  • zly9923218
  • zly9923218
  • 2016-04-11 21:31:24
  • 1763

纯jsp,struts1,struts2,springMvc开发性能对比篇

看了几篇关于三者的性能比较的文章:(这些文章和测试我并没有做过实验,仅用于参考)   结论如下:   注:测试都没有数据库,也没有复杂业务,action和jsp中内容很简单,目的就是测试MVC部分...
  • u011921490
  • u011921490
  • 2014-06-23 10:31:44
  • 1361

Servlet、Struts1、Struts2线程安全

对java servlet 单例模式的理解 理解两个问题足以,问题如下: 1、如果不同的2个用户同时对这个网站的不同业务同时发出请求(如注册和登陆),那容器里有几个servle...
  • E01014165
  • E01014165
  • 2016-07-17 10:47:57
  • 262

SpringMVC和Struts2并发访问时的线程安全问题

SpringMVC是基于方法的拦截,Struts2是基于类的拦截。 Struts2每处理一个请求,就会实例化一个Action对象,所有不会有线程安全的问题。 SpringMVC的controlle...
  • tensionsky
  • tensionsky
  • 2017-02-10 17:31:32
  • 3525

struts1 和struts2 线程安全

首先我们必须要先了解servlet的生命周期: 服务器只创建每个servlet的单一实例,首次创建servlet时,它的init方法会被调用,因此,init是放置一次性设置代码的地方,之后,针对...
  • zljjava
  • zljjava
  • 2012-05-14 17:18:48
  • 8040

SpringMVC、Struts1和Struts2区别

1、 springMVC单例非线程安全,struts1单例非线程安全,struts2线程安全对每个请求都产生一个实例。 2、 springMVC和String1的入口都是servlet,而strut...
  • wan23333
  • wan23333
  • 2017-11-29 20:45:00
  • 292

Struts 1 和 Struts 2 的线程安全

Action类Struts 1要求Action类要扩展自一个抽象基类。Struts 1的一个共有的问题是面向抽象类编程而不是面向接口编程。 Struts 2的Action类实现了一个Action接口,...
  • For_living
  • For_living
  • 2010-10-30 23:31:00
  • 398

servlet、struts1和struts2的线程安全问题

一、servlet和struts1 通常情况下,系统只生成servlet的单一实例之后,为每个用户请求建立新的线程。如果很多请求同时到来,那么多个线程可能会并发的访问同一个servlet对象。因此必...
  • woshixuye
  • woshixuye
  • 2013-04-23 17:09:20
  • 1504

struts1单例线程不安全struts2多例线程安全

转载:http://zhidao.baidu.com/link?url=hM6wMRIOGs7nRkrBSKVjqp6wMNzBd7B7gfnthPbarN1YXgtulKcx9Oqej2VYW-HT...
  • zhangzhangjava
  • zhangzhangjava
  • 2016-04-25 15:21:10
  • 1717

struts1.x、struts2.x、Spring MVC原理总结

Struts1原理 初始化:struts框架的总控制器ActionServlet是一个Servlet,它在web.xml中配置成自动启动的Servlet,在启动时总控制器会读取配置文件(st...
  • worthliu
  • worthliu
  • 2016-06-06 17:23:17
  • 695
收藏助手
不良信息举报
您举报文章:聊聊Servlet、Struts1、Struts2以及SpringMvc中的线程安全
举报原因:
原因补充:

(最多只允许输入30个字)