由于系统采用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!
虾皮二面:Spring Bean 默认是单例的,如何保证并发安全?
Spring 的 Bean 默认都是单例的,某些情况下,单例是并发不安全的,以 Controller 举例,问题根源在于,我们可能会在 Controller 中定义成员变量,如此一来,多个请求来临,进入的都是同一个单例的 Controller 对象,并对此成员变量的值进行修改操作,因此会互相影响,无法达到并发安全(不同于线程隔离的概念,后面会解释到)的效果。 首先来举个例子,证明单例的并发不安全性:
面试官:Spring MVC 如何保证 Controller 的并发安全性?面试必问。。
单例模式(Singleton)是程序设计中一种非常重要的设计模式,设计模式也是Java面试重点考察的一个方面。
Spring Boot 使用 Redis 提升天气预报应用的并发访问能力
有时,为了提升整个网站的性能,我们会将经常需要访问数据缓存起来,这样,在下次查询的时候,能快速的找到这些数据。 缓存的使用与系统的时效性有着非常大的关系。当我们的系统时效性要求不高时,则选择使用缓存是极好的。
背景:前台页面通过时间插件(My97Date)传递时间作为过滤条件筛选订单列表、请求一直报400. 分析:前台传递的时间类型为String、 后台对应的订单实体里为Date类型、所以参数不匹配? 所以又在实体里定义了两个String类型的时间变量; 结果请求果然通了。而且时间也自动封装到对象里去了、恩。。 接下来通过DateFormat 来把时间格式 <h1 id="多事务运行并发问题">多事务运行并发问题</h1> <p>在实际应用中,往往是一台(或多台)服务器向无数客户程序提供服务,当服务器查询数据库获取数据时,如果没有采用必要的隔离机制,可能会存在数据库事务的并发问题,下面是一些常见的并发问题分类:</p> <pre><code>1. 第一类丢失更新:撤销一 &lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;beans xmlns="http://www.springframework.org/schema/b