ThreadLocal实现线程范围内的共享变量,当多线程过沉重,容易出现共享数据被别的线程操作,导致脏数据发生,ThreadLocal本质上讲是提供了一个“线程级”变量作用域

private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();

存:threadLocal.set(data);

取:threadLocal.get();

 

set时,先获取当前线程,然后获取当前线程的ThreadLocal Map,ThreadLocal Map会存储数据,采用类似HashMap机制,存储以threadLocal为key,需要隔离的数据为value的Entry键值数组结构,

get时,先获取当前线程,然后获取到当前线程的threadLocal Map对象,如果非空,那么取出threadLocal的value,否则初始化

实际应用

一.Spring MVC默认是单例模式,Controller、Service、Dao都是单例所以在使用不当存在一定的安全隐患。Controller单例模式的好处在与: 
1. 提高性能,不用每次创建Controller实例,减少了对象创建和垃圾收集的时间 
2. 没多例的必要 
二.由于只有一个Controller的实例,当多个线程同时调用它的时候,它的成员变量就不是线程安全的。 
当然在大多数情况下,我们根本不需要Controller考虑线程安全的问题,除非在类中声明了成员变量。因此Spring MVC的Contrller在编码时,尽量避免使用实例变量。如果一定要使用实例变量,则可以改用以下方式: 
1. Controller中声明 scope=”prototype”,即设置为多例模式 
2.在Controller中使用ThreadLocal变量,如:private ThreadLocal<Integer> count = new ThreadLocal<Integer>();
三.springmvc singleton有几种解决方法:
1、在控制器中不使用实例变量(可以使用方法参数的形式解决,参考博文 Spring Bean Scope 有状态的Bean 无状态的Bean)
2、将控制器的作用域从单例改为原型,即在spring配置文件Controller中声明 scope="prototype",每次都创建新的controller
3、在Controller中使用ThreadLocal变量

四.spring中的并发访问题:

我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。
那么对于有状态的bean呢?Spring对一些(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态的bean采用ThreadLocal进行处理,让它们也成为线程安全的状态,因此有状态的Bean就可以在多线程中共享了。

spring对那些个有状态bean使用ThreadLocal维护变量[仅仅是变量,因为线程同步的问题就是成员变量的互斥访问出问题]时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

 

何时用ThreadLocal

如果在Controller中的定义一个变量,并且定义成多例模式,那么可以用ThreadLocal包裹此变量,提供“线程级”变量作用域,以保证线程安全。