源码浅析—ThreadLocal
Posted xitingfeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了源码浅析—ThreadLocal相关的知识,希望对你有一定的参考价值。
一、ThreadLocal它是什么?有什么作用?
ThreadLocal 是一个存储了线程独有变量的类。
二、它是如何存储线程独有变量的呢?
ThreadLocal 主要是通过自身的一个静态内部类 ThreadLocalMap,对当前线程的变量进行存储的。
首先我们来看一下这个静态内部类:
那看完了他们的结构关系,我们来看看它是如何 存值 的:ThreadLoacal 中的 set 方法
public void set(T value) {
Thread t = Thread.currentThread(); // 获取当前线程
ThreadLocalMap map = getMap(t); // 获取当前线程独有的 ThreadLocalMap
if (map != null)
map.set(this, value); // 当前线程对象作为 key,存放键值对
else
createMap(t, value);
}
分析:注意看,里面调用了一个方法: getMap(Thread t),看到这个方法,我们就可以联想到刚刚提到的 ThreadLocalMap,点进去看一下!
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
分析:原来它是返回了传入参数的线程内部的 threadLocals 这个属性,点过去看一下!
看到这里,我们就有些明白了。它实际上,是将当前线程对象获取出来,然后把当前线程对象作为key,以 key:value 的形式存入到它的静态内部类中的 Entry 数组中去了。
三、Entry 为什么使用了弱引用呢?
一开始看整体结构的时候,我们就发现了,Entry 数组它继承了 弱引用类,那原因是什么呢?
举个例子:首先在 main 线程中定义一个方法,里面创建一个 ThreadLocal对象,进行存取值
public void func1() {
ThreadLocal t = new ThreadLocal<Integer>();
t.set(1);
t.get();
}
然后我们观察一下:
分析:我们观察可以看见,main 线程的栈中有个栈帧,里面的 ThreadLocal 对象 t 指向了它内部的 ThreadLocal,而 ThreadLocalMap 的 Entry 数组中的 key,也是当前线程对象,也指向了 ThreadLocal。
做一个假设,Entry不使用弱引用:如果方法执行结束,栈帧销毁,那么强引用就没了。但是静态内部类中的成员Entry的引用还在,如果我们不声明为弱引用,那么默认的强引用,将会导致该 ThreadLocal 对象一直不能被回收,将会导致内存泄漏,而弱引用就不同了,一旦栈帧中的对象销毁,该对象只要被GC线程发现,就会被回收了!
参考博客:https://www.cnblogs.com/shen-qian/p/12108655.html
以上是关于源码浅析—ThreadLocal的主要内容,如果未能解决你的问题,请参考以下文章
阿里架构师浅析ThreadLocal源码——黄金分割数的使用