【原理/Java并发】简单理解ThreadLocal

1. 理解

  • ThreadLocal用来隔离开每个Java线程的存储空间。它本身并不存储数据,真正通过ThreadLocal存储的数据都放在了线程对象的叫ThreadLocals的一个ThreadLocalMap表里(没实现Map接口,使用开发定址法解决哈希冲突,索引直接+1或者如果如果在Entry[]里最后一个位置冲突就去0):
    请添加图片描述
  • 可以把ThreadLocal对象理解成是一个中介,其实就是上面这个threadLocals中的key,对应的value就在你调用ThreadLocal对象的set(value)方法所在的线程对象内部threadLocals表中,获取时直接用这个线程再调用相同的ThreadLocal对象的get()方法就行了。
  • 更容易理解其实就差不多是:
    threadLocal0.set(value) = Thread.currentThread().threadLocals.set(threadLocal0, value)
    threadLocal0.get() = Thread.currentThread().threadLocals.get(threadLocal0)

2. 使用

  • 既然ThreadLocal对象就相当于一个key,你只要能找到它就行。比如作为一个类的静态成员变量,取到这个ThreadLocal对象进行get或set就好。
  • 不过平时自己用的机会可能也不多,个人理解主要使用在不方便通过方法调用传值的情况。比如Spring的切面:在Spring容器里创建的对象不是我们自己写的,是被动态代理过的。每个切面之间传递变量不方便,但是这些切面和原始方法的执行都是通过同一个线程,这个时候就是一个很方便的ThreadLocal使用场景。
  • 再具体点的例子,@Transactional注解很常用,但是原始方法是如何取得相同连接的呢?再实际调方法时,Spring会为我们的业务方法执行前加入TransactionInterceptor进行拦截,这其中会给线程绑定事务信息和jdbc的Connection。之后使用Mapper进行数据库操作获取连接(通过SqlSession,也被Spring代理了,这样可以获取绑定到的事务),再进行操作就实现了事务管理。

    * Spring事务原理解析

3. 内存泄漏问题

  • 在Entry[]里面,key值用弱引用指向了ThreadLocal对象,这样使垃圾清理的时候就会清理掉key。
  • 但是一般使用的时候这个ThreadLocal对象都是作为一个类的静态成员变量,类的对象一般不会轻易被垃圾回收(只有当这个类的类加载器,类的Class对象,以及所有实例都不再被引用才会被回收),这样导致ThreadLocal也不会被回收。如果持有线程长时间运行,就会一直占用内存,可能会内存溢出。
  • 即使ThreadLocal对象的已经没有强引用了,它在Entry中对应的value依然是强引用。发生gc会清理掉key,value依然会保留在内存中。只有当下次要获取或者设置这个索引位置时才会清理掉引用。
  • 所以一定要手动使用remove来进行清理。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值