ThreadLocal使用与如何避免内存泄漏

ThreadLocalMap数据结构

  与其他map相类似,ThreadLocalMap内部存储的数个格式也是<k, v>形式的。不同点在于,ThreadLocalMap的key设置的当前线程,value设置的是继承自弱引用类型的WeakReference的Entry对象。
在这里插入图片描述
  通过阅读源码,不难发现。ThreaLocalMap在使用的时候。其实都是在方法内部,获取到了本地线程,进行操作的。
在这里插入图片描述
在这里插入图片描述
  ThreadLocalMap整体的数据结构可以理解为一个只能存放单个key对象的map集合。

ThreadLocal使用场景

ThreadLocal的使用场景,其实比较容易。首先得知道ThreadLocal得特性才行。
特性比如:

  • 线程私有,不可共享
  • 只能存放单个值对象
    所以总体而言,一般这个容器,可以用来存放仅供当前线程使用,但又不方便(或者没必要)进行重复值传递得对象。
    比如说:
  • 已有得系统上,需要接入多租户信息,为了达到数据操作时,有数据级别的隔离。这时候,我们要么在原有系统上,进行大刀阔斧得,每个查询、新增、修改方法都需要加上租户。不如直接使用spring得aop特性。在接口得初始化调用时,存放到统一得map中,在sql查询时拦截sql进行拼接。

ThreadLocal产生内存泄漏的原因

首先内存泄漏是什么东西呢?
  内存泄漏是程序在申请内存后,无法释放已申请的内存空间,多次内存泄漏就会导致内存耗光的严重问题。
  在这里就有个概念了,在Java中存在多种应用对象。
  强引用:使用最普遍的引用(new),一个对象具有强引用,不会被垃圾回收器回收。当内存空间不足,java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不回收这种对象。
  如果想取消强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样可以使JVM在合适的时间回收该对象。

  弱引用:JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。可以在缓存中使用弱引用。

  我们的ThreadLocal存放得entry就是被WeakReference标记得弱引用类型对象。

  ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal不存在外部强引用时,key(ThreadLocal)就会被GC回收,这样就会导致ThreadLocalMap中key为null,而value还存在强引用,只用thread线程退出,value的强引用链条才会断掉,但如果当前线程未结束,这些key为null的Entry的value就会一直存。
  如果ThreadLocalMap的key为强引用回收ThreadLocal时,因为ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal就不会被回收,导致Entry内存泄漏。

  ThreadLocalMap的key为弱引用回收ThreadLocal时,由于ThreadLocalMap持有ThreadLocal的弱引用,即使没有手动删除,ThreadLocal也会被回收。当key为null,在下一次ThreadLocalMap调用set(),get(),remove()时会清除value的值。

  因此,ThreadLocal内存泄漏的根源是由于ThreadLocalMap的生命周期和Thread一样长,如果没有手动删除对应key就会导致内存泄漏,而不因为弱引用。

如何避免ThreadLocal产生的内存泄漏

ThreadLocal正确的使用方法:

  1. 每次使用完ThreadLocal都要调用它的remove()清除数据。
  2. 将ThreadLocal变量定义成private static,这样就一直存在ThreadLocal的强引用,也能保证任何时候都能通过ThreadLocal的弱引用访问到Entry的value值,进而清除掉。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的ThreadLocal变量是一种线程本地变量,它提供了一种在多线程环境下保持变量的独立副本的机制。每个线程都可以独立地修改自己的副本,而不会影响其他线程的副本。这种机制可以避免线程安全问题,并且在某些情况下可以提高性能。 然而,如果在使用ThreadLocal变量时不小心处理,可能会导致内存泄漏内存泄漏是指在程序中不再使用的对象仍然占用内存空间,无法被垃圾回收器回收,从而导致内存的浪费。 为了避免ThreadLocal变量的内存泄漏,我们需要注意以下几点: 1. 及时清理:在使用ThreadLocal变量后,应该及时调用remove()方法将其从当前线程中移除。这样可以避免变量的副本一直存在于线程中,占用内存。 2. 使用try-finally块:为了确保在任何情况下都能正确地清理ThreadLocal变量,可以使用try-finally块来确保在使用完后进行清理操作。 下面是一个示例代码,演示了如何正确使用ThreadLocal变量并避免内存泄漏: ```java public class ThreadLocalExample { private static ThreadLocal<String> threadLocal = new ThreadLocal<>(); public static void main(String[] args) { try { threadLocal.set("Hello, ThreadLocal!"); // 使用ThreadLocal变量 System.out.println(threadLocal.get()); } finally { // 清理ThreadLocal变量 threadLocal.remove(); } } } ``` 在上面的示例中,我们使用了try-finally块来确保在使用ThreadLocal变量后进行清理操作。在finally块中调用remove()方法将变量从当前线程中移除,以避免内存泄漏。 总结一下,为了避免ThreadLocal变量的内存泄漏,我们需要在使用完后及时清理,并且可以使用try-finally块来确保清理操作的执行。这样可以保证ThreadLocal变量的副本不会一直存在于线程中,从而避免内存泄漏的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值