ThreadLocal的静态内部类ThreadLocalMap所使用的Entry为什么要使用弱引用,而不是强引用?

本文探讨了Java中的强引用、软引用、弱引用和虚引用在ThreadLocal使用中的影响,指出静态内部类ThreadLocalMap可能导致内存泄漏。特别强调在线程池环境下,务必调用remove方法以避免内存泄漏问题。
摘要由CSDN通过智能技术生成

前置知识:

强引用,软引用,弱引用,虚引用介绍:

        强引用是最常见的引用类型。当一个对象具有强引用时,即使内存空间不足,垃圾回收器也不会进行回收。只有在强引用不存在时,垃圾回收器才会回收该对象。

        软引用是一种比强引用更弱的引用类型。当内存空间不足时,垃圾回收器可能会回收具有软引用的对象,但并不是一定会回收。软引用可以用来实现缓存功能。

        弱引用是一种比软引用更弱的引用类型。当对象只有弱引用时,只要有gc就回收该对象,即使内存空间不紧张。弱引用通常用于实现对象的事件监听和缓存功能。

        虚引用是最弱的一种引用类型。当对象只有虚引用时,垃圾回收器会确保在回收该对象之前,先通知相关的引用对象。虚引用主要用于在对象被回收时进行一些清理工作。
提供一种比finalize更灵活的机制。

分析:

        线程栈中的自定义的ThreadLocal变量指向了堆中的ThreadLocal实例对象,这是毫无疑问的强引用,且如果只存在这一对引用关系,则线程销毁,ThreadLocal变量被GC回收的同时,堆中的实例对象也会被销毁,不会存在内存泄漏的问题。
        但是,由于静态内部类ThreadLocalMap所使用的kv键值对,是以ThreadLocal引用的形式作为key,因此如果没有手动remove,那自然ThreadLocalMap就中会保留了一份指向堆中实例对象的引用。按照GC的可达性分析,因为Map中还存在一份指向堆中实例对象的引用,所以即使线程销毁,堆中的实例对象就不会被销毁,这个对象将一直驻留在内存中,造成内存泄漏。
        而如果Map中的引用是弱引用,则只要垃圾回收开始,即使内存还存在一个弱引用指向堆中的实例对象,这个实例对象依然会被销毁,这样可以解决大多数的内存泄漏问题,但并不完美。

        因为此时Map中的key就会指向null,这会导致新的问题。

        分析:如果此时线程直接结束,万事大吉,因为value值的引用只存在当前线程的工作内存中,一旦线程销毁,关于堆中value对象的强引用也会随之销毁,进而销毁堆中的value实例对象。

        但是,如果在线程池环境下,当前线程并不会被销毁,而是继续下一个任务。这将导致
Map中始终存在一个key=null,value=xxx的键值对。而value实例对象和对应的强引用就会一直驻留在内存中,造成内存泄漏。 

       解决方案:ThreadLocal的set,get,remove方法会自动扫描Map,将key=null的键值对的value设置为null,从而清除value到堆中实例对象的强引用链,交给
垃圾回收线程自动回收。

        总结:在线程池环境下使用ThreadLoacl,一定要记得最后调用remove方法,以避免业务混乱和内存泄漏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值