简单定义和代码
ThreadLocal 提供线程本地变量。方式变量的线程安全问题。
猜测实现方式是使用map,保存线程中本地变量的内容,废话不多直接先上代码。
资源类,定义了一个ThreadLocal变量,初始化为0,。以及针对该变量的一些操作。
从运行结果可以看出来,三个线程,每个线程都会操作自己线程中的ThreadLocal,相互之间不干扰。
源码分析
本文大部分截图,以及概念都引用了这篇博客,有需要的小伙伴直接传送过去:https://www.cnblogs.com/fsmly/p/11020641.html
在ThreadLocal有一个内部类,ThreadLocalMap。而在线程中,存在如下的变量。
又上可知,每个线程的本地变量都存在都存在该县城 threadLocals 变量中,它的类型是 ThreadLocal中的内部类,ThreadLocalMap。如果当前线程一直不消亡,那么这些本地变量就会一直存在(所以可能会导致内存溢出),因此使用完毕需要将其remove掉。
ThreadLocal 中提供了对本地变量的相关操作
1、初始化,没什么好说的就是提供了初始化本地变量的方法。
2、get方法,ThreadLocalMap是否存在,存在返回其中本地变量,不存在创建一个。
3、set方法
4、remove方法
5、ThreadLocalMap类似于一个hashMap的存在。是ThreadLocal的内部类,本文没有深入研究起源吗,有兴趣的小伙伴可以自行研究一下(只要是我懒,并且不想看)。
继承性和解决方案
ThreadLocal 是不支持继承性的,就是在父线程设置一个变量,子线程无法获取到这个变量。上代码:
从运行结果可以看出来,子线程获取threadLocal 是 null,而父线程中的是 Ok。如何解决该问呢,这时候就用到了ThreadLocal的子类 InheritableThreadLocal,修改后如下:
简单分析一下 InheritableThreadLocal。
从上图可知,InheritableThreadLocal 初始化的时候,操作的是线程中 inheritableThreadLocals变量,而不是之前的threadLocals变量。同时重写了 childValue 方法,在其父类ThreadLocal中,
是这样抛出一个异常的。
查看Thread 的init源码可知,父线程创建子线程的时候,会查看父线程的 InheritableThreadLocals是否存在,如果存在则在创建的时候把该变量赋给子线程的InheritableThreadLocals中。
使用注意事项
使用不当会导致内存泄露,因为ThreadLocalMap中的key是弱引用,所以GC回收的时候,可能导致key被回收,但是value(Entry)还存在,就是key消失了value还存在。
避免该方法的途径,是在使用住注意使用remove对变量进行回收。