ThreadLocal

本文探讨了ThreadLocal如何避免线程安全问题,重点讲解了ThreadLocalMap的工作原理,内存泄漏的潜在风险以及如何通过弱引用来确保资源的正确清理。学习如何正确使用ThreadLocal并理解其在多线程环境中的内存管理关键。
摘要由CSDN通过智能技术生成

ThreadLocal

ThreadLocal 不是用来解决共享对象的多线程访问问题的,ThreadLocal只适用于 共享对象会造成线程安全的业务场景

ThreadLocalMap

ThreadLocalMap是ThreadLocal的静态内部类,数据存放在ThreadLocalMap.Entry里面。

thread,threadLocal,threadLocalMap,Entry之间的关系:在这里插入图片描述

Tips:实线表示强引用,虚线表示弱引用

需要注意的是Entry中的key是弱引用,当threadLocal外部强引用被置为null(threadLocalInstance=null),那么系统 GC 的时候,根据可达性分析,这个threadLocal实例就没有任何一条链路能够引用到它,这个ThreadLocal势必会被回收,这样一来,ThreadLocalMap中就会出现key为null的Entry,就没有办法访问这些key为null的Entry的value,如果当前线程再迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永远无法回收,造成内存泄漏。

Tips:在threadLocal的生命周期里,针对threadLocal存在的内存泄漏的问题,都会通过expungeStaleEntry,cleanSomeSlots,replaceStaleEntry这三个方法清理掉key为null的脏entry。

ThreadLocal的使用场景

ThreadLocal 不是用来解决共享对象的多线程访问问题的,数据实质上是放在每个thread实例引用的threadLocalMap,也就是说每个不同的线程都拥有专属于自己的数据容器(threadLocalMap),彼此不影响。因此threadLocal只适用于 共享对象会造成线程安全 的业务场景。

ThreadLocal正确的使用方法

  1. 每次使用完ThreadLocal都调用它的remove()方法清除数据
  2. 将ThreadLocal变量定义成private static,这样就能保证任何时候都能通过ThreadLocal的弱引用访问到Entry的value值,进而清除掉。

弱引用(WeakReference)

例子1:弱引用被回收

 	/**
     * 弱引用
     */
    @Test
    void weakReferenceTest() {
        User user = new User();
        WeakReference<User> userWeakReference = new WeakReference<User>(user);
        for (int i = 0; ; i++) {
            if (userWeakReference.get() != null) {
                System.out.println("对象还存活" + i + userWeakReference);
            } else {
                System.out.println("对象已被回收!");
                break;
            }
        }
    }

例子2:弱引用没有被回收

	/**
     * 弱引用
     */
    @Test
    void weakReferenceTest() {
        User user = new User();
        WeakReference<User> userWeakReference = new WeakReference<User>(user);
        for (int i = 0; ; i++) {
            System.out.println("User强引用:" + user);
            if (userWeakReference.get() != null) {
                System.out.println("对象还存活" + i + userWeakReference);
            } else {
                System.out.println("对象已被回收!");
                break;
            }
        }
    }

两个例子只相差一行,在循环中使用了强引用对象,则弱引用没被回收。

总结

  • key使用强引用

当ThreadLocalMap的key使用强引用时,此时若是外部的ThreadLocal对象被置为null,按理说应该被回收,但是ThreadLocalMap中还持有对ThreadLocal的强引用,如果没有手动删除,那么ThreadLocal不会被回收,导致Entry内存泄漏。

  • key使用弱引用

当ThreadLocalMap的key为弱引用回收ThreadLocal对象时,由于ThreadLocalMap只持有ThreadLocal的弱引用,即使没有手动删除,也不会影响ThreadLocal的回收。当key为null时,在下一个调用ThreadLocalMap的set、get、remove方法时会清除value值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值