Spring中采用公共变量并发问题解决

由于系统采用springmvc框架,springmvc核心控制器DispatcherServlet 默认为每个controller生成单一实例来处理所有用户请求,所以在这个单一实例的controller中,它的XXXService也是一个实例处理所有请求, 这样XXXService的成员变量就被所有请求共享。这样就会出现并发请求时变量内容被篡改的问题。

那么出现这种问题如何解决呢?
第一种方式: 既然是全局变量惹的祸,那就将全局变量都编程局部变量,通过方法参数来传递,但是如果多个方法都需要该参数的话,传参就相当繁琐。
第二种方式: jdk提供了java.lang.ThreadLocal,它为多线程并发提供了新思路。 (当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本)
ThreadLocal类用来提供线程内部的局部变量。这些变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量,ThreadLocal实例通常来说都是private static类型。
总结:ThreadLocal不是为了解决多线程访问共享变量,而是为每个线程创建一个单独的变量副本,提供了保持对象的方法和避免参数传递的复杂性。

父类ThreadLocal定义:

//存储MessageContentModel对象,防止对象并发覆盖
    private ThreadLocal<MessageContentModel> msgContentModelTL = new ThreadLocal<MessageContentModel>();
    //存储HandlerContext对象,防止对象并发覆盖
    private ThreadLocal<HandlerContext> contextModelTL = new ThreadLocal<HandlerContext>();

父类设置对象值:

 /**
     * 日志对象
     */
    public HandlerContext getContext() {
        return contextModelTL.get() != null ? contextModelTL.get() : new HandlerContext();
    }

    private void setContext(HandlerContext context) {
        contextModelTL.set(context);
    }

    /**
     * 消息内容服务公用模型
     */
    public MessageContentModel getMsgContentModel() {
        return msgContentModelTL.get() != null ? msgContentModelTL.get() : new MessageContentModel();
    }

    private void setMsgContentModel(MessageContentModel msgContentModel) {
        msgContentModelTL.set(msgContentModel);
    }

子类使用:

 this.getContext().writeLogTag("获取链接失败");

ThreadLocal的主要应用场景为按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。例如:同一个网站登录用户,每个用户服务器会为其开一个线程,每个线程中创建一个ThreadLocal,里面存用户基本信息等,在很多页面跳转时,会显示用户信息或者得到用户的一些信息等频繁操作,这样多线程之间并没有联系而且当前线程也可以及时获取想要的数据。

实现原理:
ThreadLocal可以看做是一个容器,容器里面存放着属于当前线程的变量。ThreadLocal类提供了四个对外开放的接口方法,这也是用户操作ThreadLocal类的基本方法:
(1) void set(Object value)设置当前线程的线程局部变量的值。
(2) public Object get()该方法返回当前线程所对应的线程局部变量。
(3) public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
(4) protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次,ThreadLocal中的缺省实现直接返回一个null。

可以通过上述的几个方法实现ThreadLocal中变量的访问,数据设置,初始化以及删除局部变量,那ThreadLocal内部是如何为每一个线程维护变量副本的呢?

其实在ThreadLocal类中有一个静态内部类ThreadLocalMap(其类似于Map),用键值对的形式存储每一个线程的变量副本,ThreadLocalMap中元素的key为当前ThreadLocal对象,而value对应线程的变量副本,每个线程可能存在多个ThreadLocal。

http://blog.csdn.net/lhqj1992/article/details/52451136

时间: 2024-10-04 15:04:48

Spring中采用公共变量并发问题解决的相关文章

asp.net网站类中public公共变量问题

问题描述 如题,在类中定义了一个public公共变量,这个公共变量可写可读,当同时多人访问时,同时向这个变量写入值,这样会相互影响,相互冲突吗?谢谢! 解决方案 解决方案二:会.不过你可以使用Lock来操作==解决方案三:不是static就没关系解决方案四:引用2楼hanjun0612的回复: 不是static就没关系 privatestringstr="abc";publicstringStr{get{returnstr;}set{str=value;}}就是这样子的,没有加stat

Spring中bean的基本xml配置

xml   在spring容器内拼凑bean叫作装配.装配bean的时候,你是在告诉容器,需要哪些bean,以及容器如何使用依赖注入将它们配合在一起.    理论上,bean装配可以从任何资源获得,包括属性文件,关系数据库等,但xml是最常见的spring 应用系统配置源.Spring中的几种容器都支持使用xml装配bean,包括:    XmlBeanFactory ,    ClassPathXmlApplicationContext ,    FileSystemXmlApplicatio

Spring中的AOP详解

本文摘自pandonix的博客.   此前对于AOP的使用仅限于声明式事务,除此之外在实际开发中也没有遇到过与之相关的问题.最近项目中遇到了以下几点需求,采用AOP来解决.一方面是为了以更加灵活的方式来解决问题,另一方面是借此机会深入学习Spring AOP相关的内容.本文是权当本人的自己AOP学习笔记,以下需求不用AOP肯定也能解决,至于是否牵强附会,仁者见仁智者见智. 面对需求: ①对部分函数的调用进行日志记录,用于观察特定问题在运行过程中的函数调用情况. ②监控部分重要函数,若抛出指定的异

javascript-js 消除公共变量 谢谢谢谢

问题描述 js 消除公共变量 谢谢谢谢 一个js文件中定义了太多的公共变量,多个方法都调用了这些变量 怎么消除这些公共变量 将方法提取出来 谢谢 解决方案 可以百度一下,看看有没有? 解决方案二: 提供思路就好 多谢大家 解决方案三: 使用require.js插件,按需加载,全部都是局部变量. 解决方案四: 如果这些方法是一个整体的话,采用闭包的方式,但如果有不是闭包内的方法间调用,则需要更改调用方法的方式. function(公共变量1,公共变量2,公共变量3){ return {a:func

Spring中属性注入详解_java

本文演示了int.String.数组.list.set.map.Date等属性的注入. 其中Date类型的注入则是借助了Spring提供的属性编辑器来实现的,首先是用到的五个实体类 package com.jadyer.model; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; /** * 常见属性的注入 * @see 包括int,String,Array,lis

Java中Clojure如何抽象并发性和共享状态

在所有 Java 下一代语言中,Clojure 拥有最激进的并发性机制和功能.Groovy 和 http://www.aliyun.com/zixun/aggregation/16945.html">Scala 都为并发性提供了改善的抽象和语法糖的一种组合,而 Clojure 坚持了它始终在 JVM 上提供独一无二的行为的强硬立场.在本期 Java 下一代 中,我将介绍 Clojure 中众多并发性选项的一部分.首先是为 Clojure 中易变的引用提供支撑的基础抽象:epochal 时间

Win7系统中的环境变量PATH怎么修改

  方法一.通过命令设置环境变量 1.打开"开始→运行",在运行框中"cmd",回车打开命令提示符窗口; 2.在打开的命令提示符窗口中,输入"path",回车就可查看环境变量设置; 3. 更改环境变量有两种情况: 一是追加方式,就是在不改变环境变量现有设置的情况下,增加变量的值,比如要给环境变量增加一个值为"D:Python"的设置,可以输入"path=%path%;D:Python";而另一种是完全修改方

ASP中轻松实现变量名-值变换

变量 用过PHP的朋友都知道,PHP中变量的使用灵活方便,特别是能在字符串中方便实现变量名-值变换,使得整个PHP代码更显简洁优美.比如一条更新数据库的SQL语句只需写成:"update users set password='$password', group=$group, name='$username' where account='$account'",其中的$password.$group.$username.$account便会被实际的变量值替换,而在ASP中要实现相同的

Oracle中如何绑定变量

oracle 中,对于一个提交的sql语句,存在两种可选的解析过程, 一种叫做硬解析,一种叫做软解析. 一个硬解析需要经解析,制定执行路径,优化访问计划等许多的步骤.硬解释不仅仅耗费大量的cpu,更重要的是会占据重要的们闩(latch)资源,严重的影响系统的规模的扩大(即限制了系统的并发行), 而且引起的问题不能通过增加内存条和cpu的数量来解决. 之所以这样是因为门闩是为了顺序访问以及修改一些内存区域而设置的,这些内存区域是不能被同时修改.当一个sql语句提交后,oracle会首先检查一下共享