ThreadLocal使用方式为在一个线程中创建一个ThreadLocal对象,使用threadLocal.set()赋值,在相同线程的另一个地方使用threadLocal.get()获取值,接下来,从源码角度分析一下ThreadLocal的实现方式以及存在的问题。
1:创建是直接new 一个对象创建出来,既然ThreadLocal与线程已经绑定(一个ThreadLocal在不同的线程之中可以存放不同的值),接下来看下ThreadLocal与线程是如何进行绑定的
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
以上是ThreadLocal的set方法,先获取到当前的线程,然后通过getMap(t)获取到当前线程的ThreadLocalMap,ThreadLocalMap是ThreadLocal的静态内部类,在getMap()方法中可以看到ThreadLocalMap其实是Thread的一个属性(每一个线程都有自己专属的ThreadLocalMap)。
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
ThreadLocalMap其实就是一个Map类型的,其中key是ThreadLocal,value是Entity,Entity类的格式如下:
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
ThreadLocalMap的其余地方可以不看,主要看下Entry!!!,此类继承了WeakRegerence(虚引用!!),其中此类的value就是我们要保存的值。
因此我们使用ThreadLocal.set方法保存一个值得时候,最终其实就是保存在每个线程专属的Map中,其中key为我们创建的ThreadLocal对象,这下可以明白为什么在多线程之中可以ThreadLocal可以保证线程安全,追踪到底其实就是将在不同线程之中set的值保存到了各自对应线程之中的Map之中,其中key就是ThreadLocal对象本身,也就解释了为什么一个ThreadLocal只能设置一个值,不允许设置多个值。
以上就是ThreadLocal 赋值的流程,如果把这个流程理解清楚,即使不看源码,想必大概get的方法也能猜到了,无非就是获取当前线程的ThreadLocalMap方法,然后通过此map的get(key)获取到值,其中key是当前的ThreadLocal对象。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
以上是get()的源代码,与我们预想的差不多,只不过加了双重保险,获取的map是空的话会先初始化值进去再返回初始化之后的值,获取值的方法变为了ThreadLocalMap自定义的getEntry方法,获取Entry之后其属性value就是我们在ThreadLocal的set()方法中设置的值。
至此,ThreadLocal的源码就分析了个差不多,但是,使用ThreadLocal的过程中,可能还会出现一种问题:内存泄漏
来源:CSDN
作者:weixin_41818715
链接:https://blog.csdn.net/weixin_41818715/article/details/103751474