博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
聊聊Servlet、Struts1、Struts2以及SpringMvc中的线程安全
阅读量:5962 次
发布时间:2019-06-19

本文共 3501 字,大约阅读时间需要 11 分钟。

006

前言

很多初学者,甚至是工作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实例的内存模型抽象为下图所示的模型。

3

线程安全

Servlet

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

Servlet的多线程机制

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

1

这样,当两个或多个线程同时访问同一个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://oynax.baihongyu.com/

你可能感兴趣的文章
提高信息安全意识对网络勒索病毒说不
查看>>
英国政府可能利用曼彻斯特自杀袭击要求互联网公司破解加密
查看>>
Mozilla 将大幅简化火狐浏览器的同步操作
查看>>
微软加大在 Edge/IE 浏览器上阻止 SHA-1 证书的力度
查看>>
龙芯将两款 CPU 核开源,这意味着什么?
查看>>
《51单片机应用开发从入门到精通》——导读
查看>>
iOS深拷贝与浅拷贝
查看>>
mysql5.6参数说明
查看>>
[转]线程安全的单例模式
查看>>
winfrom的打开窗口特效
查看>>
IOS(swift)-数据存储 · NSKeyedArchiver 归档
查看>>
TypeScript 入门指南
查看>>
mysql报错 Data truncated for column 'from' at row 1
查看>>
Monkey test确定package name的一种特殊方法
查看>>
ubuntu 12.04.4 安装 devstack
查看>>
windows10:一些虚拟化功能与vmware冲突
查看>>
Java Network Programming, Third Edition
查看>>
JXL导出Excel数据表
查看>>
数据库字段加1
查看>>
GNOME是最好的!
查看>>