简介
1. ThreadLocal是多线程中用来保存某个线程独有的操作;
2. ThreadLocal中的内容不能被其他Thread访问、不需要返回到公用内存;
API
1. get() 和 set() 方法是用来获取内容和存储内容的方法;
2. initalValue() :用来初始化变量的方法,在创建每一个ThreadLocal变量时,我们最好将其初始化为我们认为的初始值,不然他默认初始化值为NULL,后续操作时可能会出现问题;
ThreadLocal<Integer> data = new ThreadLocal<Integer>(){
@Override
protected Integer initalValue(){
return 0;
}
}
3. withInitial()静态方法:使用Java8新特性函数式编程,用于创建ThreadLocal变量并且将其初始化
ThreadLocal<Integer> data = ThreadLocal.withInitial(() ->0);
源码分析
底层源码中:ThreadLocalMap是ThreadLocal的静态内部类,并且Thread可以通过ThreadLocal访问ThreadLocalMap
get()方法
-
首次调用get()时,会调用 return setInitialValue()方法
从上述可得出 ThreadLocal、ThreadLocalMap、Thread三者的关系:
Thread对象维护着一个ThreadLocalMap的引用,而我们存储的数据就是放在ThreadLocalMap中的Entry对象中
ThreadLocal中的弱引用以及内存泄漏问题
源码
为什么要使用弱引用?
当方法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开发手册中有:
2. 用static 修饰ThreadLocal对象
3. 在使用TheadLocal对象前,先将其初始化操作;