1 .简介
ThreadLocal是一个线程的内部存储类,可以在每个线程的内部存储数据,
通俗的讲:ThreadLocal也叫做线程本地变量,ThreadLoacl为变量在每个线程中的都创建了副本,每个线程可以访问自己内部的副本变量,线程之间互不影响。
而是当某个很复杂的逻辑下的对象传递,需要在线程这个作用域内贯穿其中,用ThreadLocal可以避免这个创建多个静态类。
它的实现原理其实比较简单,每个线程中都会维护一个ThreadLocalMap,当在某个线程中访问时,会取出这个线程自己的Map并且用当前ThreadLocal对象做索引来取出相对应的Value值,从而达到不同线程不同值的效果。
从上图可知:
- 每个Thread线程内部都有一个Map
- Map里面储存线程本地对象key和线程的变量副本value
- Thread内部的Map是由ThreadLocal维护的,由ThreadLocal负责向Map获取和设置线程的变量值
2. 为什么要用到ThreadLocal
从上图可以看出,当你在一个类中使用 static 成员变量时,一定要为这个static 成员变量需要考虑线程安全问题!可能会出现(1)情况。
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别:
- Synchronized用于线程间的数据共享,利用锁的机制,使变量或代码块在某一时该只能被一个线程访问,用于在多个线程间通信时能够获得数据共享
- ThreadLocal则用于线程间的数据隔离(与数据共享正好相反),为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享
ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用(相同线程数据共享),也就是变量在线程间隔离(不同的线程数据隔离)而在方法或类间共享的场景。
一句话理解ThreadLocal,向ThreadLocal里面存东西就是向它里面的Map存东西的,然后ThreadLocal把这个Map挂到当前的线程底下,这样Map就只属于这个线程了。
3. 实现原理
1、每个Thread对象内部都维护了一个ThreadLocalMap这样一个ThreadLocal的Map,可以存放若干个ThreadLocal。
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
2、当我们在调用get()方法的时候,先获取当前线程,然后获取到当前线程的ThreadLocalMap对象,如果非空,那么取出ThreadLocal的value,否则进行初始化,初始化就是将initialValue的值set到ThreadLocal中。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}