开发者社区> fuyifang> 正文

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

简介: 由于系统采用springmvc框架,springmvc核心控制器DispatcherServlet 默认为每个controller生成单一实例来处理所有用户请求,所以在这个单一实例的controller中,它的XXXService也是一个实例处理所有请求, 这样XXXService的成员变量就被所有请求共享。
+关注继续查看

由于系统采用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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
三面“有赞”Java岗斩获offer:Spring+JVM+并发锁+分布式+算法
年末离职,年初为面试也筹备挺长一段时间,找了不少复习资料,刷了很多题在网上投了很多简历最终面试了有赞,还有幸拿到offer!
29 0
Spring Boot + @Async 太好用了,助你大大提升 API 并发能力!
Spring Boot + @Async 太好用了,助你大大提升 API 并发能力!
30 0
Spring的并发问题——有状态Bean和无状态Bean
Spring的并发问题——有状态Bean和无状态Bean,这个是一个面试常见的问题,现在总结一下提供给需要的同学
123 0
虾皮二面:Spring Bean 默认是单例的,如何保证并发安全?
Spring 的 Bean 默认都是单例的,某些情况下,单例是并发不安全的,以 Controller 举例,问题根源在于,我们可能会在 Controller 中定义成员变量,如此一来,多个请求来临,进入的都是同一个单例的 Controller 对象,并对此成员变量的值进行修改操作,因此会互相影响,无法达到并发安全(不同于线程隔离的概念,后面会解释到)的效果。 首先来举个例子,证明单例的并发不安全性:
101 0
阿里一面:Spring Bean 默认是单例的,高并发情况下,如何保证并发安全?
阿里一面:Spring Bean 默认是单例的,高并发情况下,如何保证并发安全?
83 0
面试官:Spring MVC 如何保证 Controller 的并发安全性?面试必问。。
单例模式(Singleton)是程序设计中一种非常重要的设计模式,设计模式也是Java面试重点考察的一个方面。
181 0
Spring Boot巧用 @Async 提升API接口并发能力!NB!
Spring Boot巧用 @Async 提升API接口并发能力!NB!
125 0
一种Java Spring框架里将配置文件里定义的值注入到Java变量的简单办法
一种Java Spring框架里将配置文件里定义的值注入到Java变量的简单办法
58 0
Spring Boot 使用 Redis 提升天气预报应用的并发访问能力
有时,为了提升整个网站的性能,我们会将经常需要访问数据缓存起来,这样,在下次查询的时候,能快速的找到这些数据。 缓存的使用与系统的时效性有着非常大的关系。当我们的系统时效性要求不高时,则选择使用缓存是极好的。
1729 0
+关注
fuyifang
携程旅行网技术研发中心资深研发工程师,研发Leader;CSDN博客专家;
文章
问答
视频
文章排行榜
最热
最新
相关电子书
更多
阿里特邀专家徐雷Java Spring Boot开发实战系列课程(第18讲):制作Java Docker镜像与推送到DockerHub和阿里云Docker仓库
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
相关实验场景
更多