多线程中的ThreadLocal

93 阅读1分钟

 简介

  1. ThreadLocal是多线程中用来保存某个线程独有的操作;

  2. ThreadLocal中的内容不能被其他Thread访问、不需要返回到公用内存;

API

image.png

  1. get() 和 set() 方法是用来获取内容和存储内容的方法;

  2. initalValue() :用来初始化变量的方法,在创建每一个ThreadLocal变量时,我们最好将其初始化为我们认为的初始值,不然他默认初始化值为NULL,后续操作时可能会出现问题;

ThreadLocal<Integer> data = new ThreadLocal<Integer>(){
@Override
protected Integer initalValue(){
        
return 0;
 }

}

  1. withInitial()静态方法:使用Java8新特性函数式编程,用于创建ThreadLocal变量并且将其初始化
ThreadLocal<Integer> data = ThreadLocal.withInitial(() ->0);

源码分析 

底层源码中:ThreadLocalMap是ThreadLocal的静态内部类,并且Thread可以通过ThreadLocal访问ThreadLocalMap

​编辑

​编辑

get()方法

​编辑

  • 首次调用get()时,会调用 return setInitialValue()方法

​编辑

从上述可得出 ThreadLocal、ThreadLocalMap、Thread三者的关系:

image.png

Thread对象维护着一个ThreadLocalMap的引用,而我们存储的数据就是放在ThreadLocalMap中的Entry对象中

ThreadLocal中的弱引用以及内存泄漏问题

 源码

image.png

image.png

为什么要使用弱引用?

image.png

 当方法t1执行完时,t1对ThreadLocal的强引用就不存在了,此时若ThreadLocal 与 ThreadLocalMap中的Entry是强引用关系,那么此时 ThreadLocal 和 Entry都不可以被回收(因为两者间存在强引用关系)此时变造成了内存泄漏,但如果是弱引用关系,如果外部没有强引用引用ThreadLocal则在内存不够时系统gc也会将其进行回收。

内存泄漏

除了上面说的内存泄漏外,还有可能当t1方法结束,ThreadLocal被回收,而Entry中的key是弱引用指向ThreadLocal的(key是ThreadLocal),此时 key被回收,但value却仍然没被回收,此时的key为null,无法调用取得value(这些key为null的Entry的value就会一直存在一条强引用链);

因此弱引用不能一定保证内存不泄露,我们要在用完某个ThreadLocal对象后,手动调用remove方法来删除他;

使用建议

  1. 使用 try finally,在finally中调用remove()方法,在阿里巴巴Java开发手册中有:

​编辑

  1. 用static 修饰ThreadLocal对象

image.png

  1. 在使用TheadLocal对象前,先将其初始化操作;