介绍:
ThreadLocal是一种避免多线程访问出现线程不安全的方法,当我们创建一个变量后,如果每个线程对其访问的时候都是线程自己的变量,这样就可以避免线程不安全问题,这就是ThreadLocal所做的。
ThreadLocal他提供线程本地变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。如果创建一个ThrealLocal变量,那么访问这个变量的每个线程都会有一个这个变量的副本。在实际多线程操作的时候,操作的是自己本地内存的变量。
我们再来看一下ThreadLocal<>类中的方法就更加清晰了,具体含义往下看。
原理:
在学习ThreadLoacl原理之前,我们应该搞明白Thread、ThreadLocal、ThreadLocalMap这三个概念和他们之间的联系。
Thread有ThreadLocal.ThreadLocalMap类型的属性threadLocals。源码如下:
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocalMap是ThreadLocal的一个内部类,ThreadLocalMap中用于存储数据的entry定义代码:
从中我们可以看到这个Map的key是ThreadLocal的一个实例对象,value则是具体的值
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
由ThreadLocal对Thread的ThreadLocalMap赋值
/**
* Create the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @param firstValue value for the initial entry of the map
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
我们再来看一下ThreadLocal里面的方法具体含义:
ThreadLocal类核心方法set、get、initialValue、withInitial、setInitialValue、remove:
(1)set方法源码解释:
public void set(T value) { //设置当前线程对应的局部变量值
//获取当前的线程
Thread t = Thread.currentThread();
//先取出当前线程对应的threadLocalMap这个属性值
ThreadLocalMap map = getMap(t);
//如果它不是空,则将value放入以this,即以threadLocal对象为key的映射的map中
if (map != null)
map.set(this, value);
else
//否则则创建一个
createMap(t, value);
}
上述方法调用了getMap()方法
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;//返回线程自己的变量ThreadLocalMap类型的threadLocals
并绑定到当前线程的成员变量ThreadLocal上
}
(2)get方法:get该方法返回当前线程所对应的线程局部变量。和set类似,也是先取出当前线程对应的threadLocalMap,如果不存在则创建一个,但是是用inittialValue作为value放入到map中,且返回initialValue,否则就直接从map取出this即threadLocal对应的value返回。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
//如果ThreadLocal不为空,就在map中查找本地变量值
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//threadLocals为空,就调用更改初始化当前线程的threadLocals变量
return setInitialValue();
}
参考博客:https://blog.youkuaiyun.com/lufeng20/article/details/24314381
https://zhuanlan.zhihu.com/p/61587053