ThreadLocal类重点
首先,来看看ThreadLocal类的类结构图,框出部分比较重要,后文会涉及相关内容。
Thread是如何与ThreadLocal关联上的?
ThreadLocal类维护一个静态内部类ThreadLocalMap,而ThreadLocalMap又维护一个静态内部类Entry,见ThreadLocal源码如下:
再看Thread类源码,Thread类持有一个ThreadLocalMap类型放入引用,并赋为null值。
Thread与ThreadLocal是通过ThreadLocal的set()和get()方法关联上的
set()方法源码:
该方法主要完成以下几件事:
- 获取当前线程实例t
- 调用getMap方法,该方法内部获取Thread类的属性ThreadLocalMap的实例
- 为ThreadLocalMap属性赋值
–map不为空时,则把值存放map,需要注意的是,map的key放入的是this,这个this代表的是当前的ThreadLocal的实例
–map为空时,创建新的ThreadLocalMap对象赋给Thread类的ThreadLocalMap属性引用。
再来看get方法:
逻辑反着来:获取当前线程实例t,通过t来拿到其ThreadLocalMap类型属性的引用map,把key(即163行的this,同理,这里的this指的是当前的ThreadLocal类的实例)传进去获取value值。如果map为空,则利用setInitialValue()方法设置初始值并返回:
需要注意的是上述方法中的initialValue()方法:
该方法是protected类型,默认返回空,实现了ThreadLocal的子类需要覆盖该方法来设置初始值
从上述一系列过程,可以得出结论
ThreadLocalMap是关联Thread和ThreadLocal的桥梁,而实现关联的关键步骤主要在于为Thread类的ThreadLocalMap类型属性赋值的过程。
WeakReference类型有什么作用?
再回来看ThreadLocalMap的源码,其持有一个Entry类型的数组,这个Entry类型就是其静态内部类。这个Entry()数组table:数组的每一个元素是一个Entry类型,而这个Entry类型元素,继承了WeakReference<ThreadLocal<?>,从Entry的构造器可以看出该Entry的key是ThreadLocal类型,value是Object类型。因为继承了WeakReference,从而可以在调用构造器的时候,首先利用父类的构造器将其key值类型ThreadLocal包装成WeakReference类型。
jdk1.2以后,引用就被分为四种类型:强引用、弱引用、软引用和虚引用。强引用就是我们常用的Object obj = new Object(),obj就是一个强引用,指向了对象内存空间。当内存空间不足时,Java垃圾回收程序发现对象有一个强引用,宁愿抛出OutofMemory错误,也不会去回收一个强引用的内存空间。而弱引用,即WeakReference,意思就是当一个对象只有弱引用指向它时,垃圾回收器不管当前内存是否足够,都会进行回收。反过来说,这个对象是否要被垃圾回收掉,取决于是否有强引用指向。ThreadLocalMap这么做,是不想因为自己存储了ThreadLocal对象,而影响到它的垃圾回收,而是把这个主动权完全交给了调用方,一旦调用方不想使用,设置ThreadLocal对象为null,内存就可以被回收掉。
如何避免内存泄漏?
为了避免内存泄漏,当对象不再使用时,需要销毁,对于我们而言,需要把对象的引用设置为null。在本文讲述的内容中,主要把两种对象的实例设置为null,一是当前线程实例,因为当前线程在run方法执行结束后会自动销毁,因为不必手动设置,二是ThreadLocal类的实例,如何销毁->利用remove()方法:
remove方法会获取当前线程内部的ThreadLocalMap,存在则从map中删除这个ThreadLocal对象
为何使用静态内部类?
在ThreadLocal类的设计过程中使用到了静态内部类,我认为主要是需要利用静态内部类的一些好处
参考:https://blog.****.net/cd18333612683/article/details/79129503#commentBox
本文参考了以下内容:
1.源码
2.https://mp.weixin.qq.com/s/vURwBPgVuv4yGT1PeEHxZQ
3.https://www.cnblogs.com/my376908915/p/6763210.html
4.https://www.jianshu.com/p/30ee77732843