ThreadLocal

ThreadLocal常用于创建线程局部变量,如在每个线程中创建单独的对象实例,避免参数传递。然而,如果不正确使用,可能导致内存泄露,因为其内部Map的value是强引用。为防止内存泄露,应当在不再需要ThreadLocal时调用remove方法。ThreadLocalMap的key使用弱引用,以便在GC时回收,而value保持强引用以保持键值对的完整性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

两大使用场景-ThreadLocal的用途

场景1: 每个线程需要一个独享的对象(通常是工具类,典型需要使用的类有SimpleDateFormat和Random)

场景2: 每个线程内需要保存全局变量(例如在拦截器中获取用户信息),可以让不同方法直接使用,避免参数传递的麻烦。

ThreadLocal

数据结构

在这里插入图片描述

 static class ThreadLocalMap {
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

主要方法介绍

  • T initialValue():
  • 初始化 void set(T t):
  • 为这个线程设置一新值 T get():得到这个线程对应的value。如果是首次调用get()。则会调用initialize来得到这个值
  • void remove(): 删除这个线程得到的值

ThreadLocal使用问题内存泄露

什么是内存泄露

某个对象不再有用,但是占用的内存却不能被回收。

Value的泄露

ThreadLocalMap 中使用的 key 为弱引用,而 value 是强引用

弱引用的对象拥有更短暂的生命周期,在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会进行回收
所以,如果 ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候,key 会被清理掉,而 value 不会被清理掉。这样一来,ThreadLocalMap 中就会出现 key 为 null 的 Entry。假如我们不做任何措施的话,value 永远无法被GC 回收,这个时候就可能会产生内存泄露。

ThreadLocalMap 实现中已经考虑了这种情况,在调用 set()、get()、remove() 方法的时候,会清理掉 key 为 null 的记录。使用完 ThreadLocal 方法后 最好手动调用remove()方法

如何避免内存泄露呢?

调用remove方法,就会删除对应的Entry对象,可以避免内存泄露,所以使用完ThreadLocal之后,应该调用remove方法。

key为什么要设置成弱引用?

ThreadlocalMap是和线程绑定在一起的,如果这样线程没有被销毁,而我们又已经不会再引用,那么key-value的键值对就会一直在map中存在,这对于程序来说,就出现了内存泄漏。
为了避免这种情况,只要将key设置为弱引用,那么当发生GC的时候,就会自动将弱引用给清理掉,也就是说:假如某个用户A执行方法时产生了一份threadlocalA,然后在很长一段时间都用不到threadlocalA时,作为弱引用,它会在下次垃圾回收时被清理掉。

value为什么不设置成弱引用?

如果是个弱引用,一次gc,entry对象就被回收了, 而threadlocalmap的key被threadlocal变量强引用,还存在。 就导致,通过key查到value为null

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值