Java中ThreadLocal的强弱引用讲解

前言

刷八股的时候,ThreadLocal这个地方,觉得有点奇怪,key是弱引用,value是强引用,为什么这样设置呢?

基本原理

首先我们要了解ThreadLocal的实现原理,它的底层实际上是一个类似于hashmap的ThreadLocalMap,通过Thread.currentThread()获取到当前线程的对象后,将之作为key,将要设置的值作为value存储到这个ThreadLocalMap中,而在这过程中,key使用到了弱引用,value则是一个强引用。

key为什么是弱引用而不是强引用

这一点很好理解,ThreadlocalMap是和线程绑定在一起的,如果这样线程没有被销毁,而我们又已经不会在某个threadlocal引用,那么key-value的键值对就会一直在map中存在,这对于程序来说,就出现了内存泄漏

为了解决这个内存泄漏的问题,需要将key设置为弱引用,那么在一次gc后,弱引用的对象就会被回收。因此key要设置为弱引用。

value为什么要设置为强引用

相信细心的小伙伴已经发现了,如果只是将key设置为弱引用而不将value设置为弱引用,那么value就不会内存泄漏吗?答案当然是会的。

那为什么不设置为弱引用呢?

设想一下这样一个场景,将key和value都设置为弱引用,我们知道key是当前线程的对象,我们在使用的时候,他肯定是有强引用的(比如代码中创建的ThreadLocal对象),那么如果在我们使用过程中如果发生了gc,那么key不会被回收,但是value却会被回收,这样如果后续我们还要get这个value,此时能get到吗?会get到一个null。这必然是我们不希望的。

这一点我们可以举个例子

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;

public class Test2 {
    public static void main(String[] args) throws Exception {
        Map<WeakReference<Integer>, WeakReference<Integer>> map = new HashMap<>(8);
        // 注意以下key和value的大小
        WeakReference<Integer> key = new WeakReference<>(1);
        WeakReference<Integer> value = new WeakReference<>(9999);
        map.put(key,value);
        System.out.println("put success");
        Thread.sleep(1000);
        System.gc();
        System.out.println("get " + map.get(key).get());
    }

}

你觉得上述代码的输出结果是什么?

你可能会回答,两个都是弱引用,一次gc后两个肯定都回收了,get到null?

答案确实是null,但是并不是都被回收了,不知道大家记不记得包装类型的缓存机制,int的包装类型会缓存0-127的引用,因此对于1来说,它的强引用一直存在,不会被回收,所以1的弱引用不会被回收,但是9999的被回收了,所以get到了null。

那大家想一下,把value换成8或者其他小于127的数字,上述代码会不会不一样。

相信大家已经有了答案。

通过这个例子,大家应该对上述ThreadLocal的原理的理解会更透彻。

这个例子来自博客被面试官问懵了,ThreadLocal的key为什么设置成弱引用?_threadlocal的key为什么弱引用-优快云博客

注意事项

那么value要是发生内存泄漏怎么办?ThreadLocal设计的时候已经考虑到了这一点,我们在调用set、get方法以及remove的时候,key为null的键值对会被清理,那么value也就不会内存泄漏了。因此在使用ThreadLocal的时候,记得最后一定要使用remove。

以上是个人见解,如有疏忽欢迎指出交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值