ThreadLocal的理解
为什么ThreadLocal的key为弱引用?
首先,我们需要看看ThreadLocal是如何存储数据的
ThreadLocal的基本用法
public class ThreadLocalExample {
private static final ThreadLocal<String> THREAD_LOCAL = ThreadLocal.withInitial(() -> "test");
public static void main(String[] args) {
// 或者在使用的时候进行set
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("test");
System.out.println(threadLocal.get());
}
private static void threadLocalExample() {
System.out.println(THREAD_LOCAL.get());
}
}
类似于这种,当然,我这个只是作为一个演示的例子
点进去set方法中查看,看看如何存储数据的
可视化的样子大概就是:
我们知道,弱引用是只要进行GC,就会被回收
**那么,为什么key需要使用WeakReference呢?**我认为是:当threadLocal=null之后,也就是没有强引用了,那么这个key实际上就没有用了,那么使用弱引用则能达到GC回收这个key,这样,在你下次进行set/get/remove的时候,实际上ThreadLocal就会把这些key对应的Entry做清除处理
set方法:
三个方法可以自己看一下
get方法:
get如果都没有找到的话,就会初始化一个变量,然后就会走到set方法
remove方法:
为什么ThreadLocal的Entry的value为强引用?
既然key为弱引用可以利于回收,那么value为什么不用弱引用呢?
再次强调:弱引用会在GC时被回收,不论内存够不够
示例:
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class ThreadLocalTest {
private static ThreadLocal<String> threadLocal = ThreadLocal.withInitial(() -> new String("888"));
public static void main(String[] args) throws InterruptedException {
weakReferenceValue();
internetTest();
}
private static void weakReferenceValue() throws InterruptedException {
Map<WeakReference<ThreadLocal<String>>, WeakReference<String>> map = new HashMap<>();
WeakReference<String> value = new WeakReference<>(new String("777"));
WeakReference<ThreadLocal<String>> key = new WeakReference<>(ThreadLocal.withInitial(() -> new String("888")));
map.put(key, value);
System.out.println(map.get(key).get());
System.out.println(key.get().get());
TimeUnit.SECONDS.sleep(1);
System.gc();
System.out.println(key.get().get());
System.out.println(map.get(key).get());
// 所以,实际上就是,ThreadLocalMap的Entry中key之所以为弱引用,是因为当ThreadLocal变量没有强引用的时候,能自动回收
// 并且,重新进行set等操作,会清除这个Entry,而value是强引用则是因为如果为弱引用,那么但凡有一次GC,这个值就没了
}
}
结果:
可以见到,弱引用,GC之后,就会为null,我们注释掉key.get().get()那一行,再次运行
看,出现了null,假设你去拿数据之前,来了一波GC,那么,恭喜:空指针伺候
ThreadLocal的内存泄漏?
其实看了第一个问题的解答,我们就知道,内存泄漏的概率还是比较低的
- ThreadLocal的强引用一直在,线程复用
- ThreadLocal的强引用不在,线程复用,未调用get/set/remove方法
所以,我认为概率比较低,而且大部分是我们使用ThreadLocal后,未做相应的资源清理
所以,建议用了之后,remove掉(注意,不要直接将ThreadLocal的变量置为null,因为一般ThreadLocal都为static,因为它一般只需要处理一次)
ThreadLocal里面为什么不直接内置一个Map,然后key为thread呢?
个人理解:因为这样的话,能存的变量就少了,即使能存多,也是需要 手段的,比如使用一个对象来存储数据。相较于当前的设计,差太多了。
总结
- ThreadLocal中Entry的key为什么是弱引用?
因为利于ThreadLocal的内部回收,相较于强引用,更能防止内存泄漏 - ThreadLocal中Entry的value为什么是强引用?
因为如果是弱引用什么的,如果取值之前发生了GC,那么拿到的值会为null - ThreadLocal的内存泄漏
出现的最多的,一般是:线程复用,ThreadLocal变量的强引用还在 - ThreadLocal里面为什么不直接内置一个Map,然后key为thread呢?
不够优雅吧,存多个数据需要更多的手段
若有错误之处,烦请指出,不胜感激