ThreadLocal

ThreadLocal

是什么?
线程变量,往ThreadLocal中填充的变量属于线程私有的。
public static void main(String[] args) {
        ThreadLocal<String> tl = new ThreadLocal<>();
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                tl.set(Thread.currentThread().getName() + "存入的值");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "获取到" + tl.get());
                System.out.println();
            }).start();
        }
    }
ThreadLocal中的set方法

ThreadLocal的set方法
可以看出,当调用set方法时,会先判断是否已经存在ThreadLocalMap了,如果,存在,直接往里面set值,如果不存在,会去创建一个ThreadLocalMap。

ThreadLocalMap的createMap方法

ThreadLocalMap的createMap方法
Thread类中成员变量threadLocals

可以看出,是在这里创建了一个ThreadLocalMap,并且将ThreadLocal的引用地址作为key。而创建出来的ThreadLocalMap是放到了Thread中的成员变量threadLocals,所以这也保证了每个线程获取到的threadLocals是属于本线程的。

ThreadLocalMap的构造器

ThreadLocalMap的构造器
ThreadLocalMap的构造函数里面其实是创建了一个初始容量为16的Entry数组进行数据存储,并且数据存放在数组中的索引位置是根据hashCode和length位运算得出。上面我们讲过每个线程其实都有一个单独的ThreadLocalMap实例threadLocals,结合此处可以理解为每个线程持有一个Entry类型的数组table,我们所有的读写过程其实都是操作这个数组完成的。

ThreadLocalMap的set方法

ThreadLocalMap的set方法
遍历table数组,如果查询到数组中有该ThreadLocal对应的值,那么将新值覆盖旧值;如果table数组未满,那么将值放到table数组的空位上。

ThreadLocal的get方法

ThreadLocal的get方法

ThreadLocal未获取到值情况下初始化值方法

ThreadLocal未获取到值情况下初始化值方法

根据该ThreadLocal从table中获取到对应的Entry,如果有值,将值返回回去;如果没值或者ThreadLocalMap没有获取到的话,那么先给Thread初始化一个ThreadLocalMap对象,然后给对应的的索引处存一个null进去,将该null返回回来即可。

ThreadLocal特性

ThreadLocal和Synchronized都是为了解决多线程中相同变量的访问冲突问题,不同的点是
1、Synchronized是通过线程等待,牺牲时间来解决访问冲突
2、ThreadLocal是通过每个线程单独一份存储空间,牺牲空间来解决冲突,并且相比于Synchronized,ThreadLocal具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问到想要的值。
正因为ThreadLocal的线程隔离特性,使他的应用场景相对来说更为特殊一些。在android中Looper、ActivityThread以及AMS中都用到了ThreadLocal。当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。

ThreadLocal存在的内存泄漏的问题

ThreadLocal引用图

问:当线程退出某个方法过后,该方法中创建的ThreadLocal强引用断开,但是该线程的threadLocals变量中的key依然指向了该ThreadLocal对象,导致该ThreadLocal对象不会被垃圾回收?

ThreadLocalMap用来存值的真正的对象

解决:我们知道Thread类中的threadLocals变量的类型ThreadLocalMap,但是真正存值的是ThreadLocalMap中的内部类Entry。而Entry是一个弱引用类型,且弱引用指向的对象正是Entry中的key值ThreadLocal。当ThreadLocal对象的强引用断开后,那么threadLocals中的key作为一个弱引用指向该ThreadLocal对象,当进行垃圾回收时就会被垃圾回收掉。解决了threadLocals中key的内存泄漏问题。
问:当threadLocals对象的key被清理了,但是value却还在,也会造成内存泄漏?
解决:当我们一个线程在使用了ThreadLocal对象过后,如果后面不再需要,及时调用ThreadLocal的remove方法进行清理。
问:当使用线程池时,线程使用完之后可能会遗留上次调用存在于该线程之中的私有变量?
解决:当我们使用完线程,线程退出时,及时remove掉线程的私有变量。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值