Java中的ThreadLocal为什么会导致内存泄漏?如何解决的?

1.什么是ThreadLocal

  • ThreadLocal是java.lang下面的一个类,是用来解决java多线程程序中并发问题的一种途径

  • 通过为每一个线程创建一份共享变量的副本来保证各个线程之间的变量的访问和修改互相不影响

  • ThreadLocal存放的值是线程内共享的,线程间互斥的,主要用于线程内共享一些数据,避免通过参数来传递,这样处理后,能够优雅的解决一些实际问题。

2.ThreadLocal的数据结构

Thread类对象中维护了ThreadLocalMap成员变量,而ThreadLocalMap维护了以ThreadLocal为key,需要存储的数据为value的Entry数组 ,如下

3.ThreadLocal的应用场景有哪些?

  • 日志上下文存储

  • PageHelper分页

  • 线程安全

  • 用户身份信息存储

4.内存泄漏来自哪?

会导致ThreadLocal内存泄漏的部分其实就是他在堆上存储的ThreadLocalMap中的K-V部分,ThreadLocalMap的key就是ThreadLocal对象,他有两个引用源,一个是栈上的ThreadLocal引用,一个是ThreadLocalMap中的Key对他的引用。对于value来说,他的引用就一条,就是从Thread对象过来的

  • 第一种情况:栈上的ThreadLocal Ref引用不在使用了,即方法结束后这个对象引用就不再用了,那么,ThreadLocal对象因为还有一条引用链在,所以就会导致他无法被回收,久而久之可能就会对导致OOM。

  • 第二种情况:Thread对象如果一直在被使用,比如在线程池中被重复使用,那么Thread对value的引用就一直在,那么就会导致ThreadLocalMap无法被回收。

5.解决

  • 弱引用解决第一种情况

    • 如果用了弱引用,那么ThreadLocal对象就可以在下次GC的时候被回收掉了。

  • 手动清理ThreadLocal解决第二种情况

    • ThreadLocalMap底层使用数组来保存元素,使用“线性探测法”来解决hash冲突的,在每次调用ThreadLocal的get、set、remove等方法的时候,内部会实际调用ThreadLocalMap的get、set、remove等操作。而ThreadLocalMap的每次get、set、remove,都会清理key为null,但是value还存在的Entry。

    • 当我们在一个ThreadLocal用完之后,手动调用一下remove,就可以在下一次GC的时候,把Entry清理掉

6.为什么虚拟线程尽量避免使用ThreadLocal

虚拟线程是支持ThreadLocal的,但由于可能创建的虚拟线程数量巨大,不当使用ThreadLocal可能导致内存泄漏等问题。

  • 如果需要,可以考虑使用作用域局部变量(Scope-local variables)作为替代方案。

7.什么是InheritableThreadLocal

InheritableThreadLocal 可以在**子线程中继承父线程中的值**。在创建子线程时,子线程将复制父线程中的 InheritableThreadLocal 变量。

8.什么是TransmittableThreadLocal?

  • InheritableThreadLocal是用于主子线程之间参数传递的,但必须要是在主线程中手动创建的子线程才可以,很多时候线程都是通过线程池进行创建和复用的,这时候InheritableThreadLocal就不行了。

  • TransmittableThreadLocal继承并加强InheritableThreadLocal类。用来实现线程之间的参数传递

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值