浅析ThreadLocal的底层实现【线程隔离+内存泄漏】

在这里插入图片描述

首先ThreadLocal有什么作用?

它最为突出的特点就是"线程隔离",可能你心中会疑问线程隔离是什么?此刻可以拿synchronized做对比,在并发环境下,synchronized将共享资源进行锁定,线程必须一个个的去挨个访问。而ThreadLocal它相当于每个线程都有一份该资源,然后线程之间对资源的操作是互不可见的;

可以这样说:synchronized采用的是以时间换空间的方式,而ThreadLocal采用的是以空间换时间的方式。

ThreadLocal如何使用呢?
在这里插入图片描述
第一个线程执行local.set(“1111”),然后在另外一个线程中先获取local中的值;最后在自己的线程内部设置值并获取
在这里插入图片描述
从结果可以看出,它的确做到线程隔离了。

好奇不,它怎么做到的呢?

在这里插入图片描述
查看getMap方法的具体实现
在这里插入图片描述在这里插入图片描述
📑首先调用了getMap()方法,这个方法是获取线程Thread类中的一个ThreadLocalMap属性,这个属性是一个key-value形式;它将ThreadLocal作为key,将隔离的数据作为value存入ThreadLocalMap集合中。

在这里插入图片描述

✨简单一句话就是:将ThreadLocal和隔离数据作为key-value,存入了Thread中的ThreadLocalMap集合中,所以只能本线程访问,因此做到了线程隔离。

❓ThreadLocalMap的内部实现是怎么样的?

ThreadLocalMap是ThreadLocal的一个静态内部类,你会发现它内部的Entry居然是一个弱引用的一个子类(Entry不用多说,了解过Map的都明白)

在这里插入图片描述
❓为什么Entry节点要继承弱引用,而不是强引用呢?

在这里插入图片描述
当我们不再使用这个ThreadLocal时,直接将t=null即可;此时ThreadLocal只有一个弱引用与之相连,而弱引用指向的对象在GC时就会被回收;所以使用WakeRefenence一定程度上避免了内存泄漏。

在这里插入图片描述
ThreadLocal为空,则key=null;此时有一个大问题,key一旦为null,那么value将无法获取;除非线程结束,否者它将一直存在,这时一个隐含的内存泄漏问题。官方对其也进行了优化,在ThreadLocal的get/set方法中,会清除所有key=null的value。

虽然官方已经做出了优化,但是使用线程池还是会内存泄漏的隐患,线程使用完之后直接放回到了线程池,此时线程存活->ThreadLocalMap存活->数据存活;这就导致了内存泄漏,所以最后的办法就是使用完ThreadLocal及时remove掉数据。

❓如果避免上面的内存泄漏?

📑在使用完ThreadLocal时,及时调用它的的remove方法清除数据。

❓ThreadLocal的使用场景?

📑如果希望将类的某个静态变量与线程状态关联,可以考虑使用ThreadLocal。ThreadLocal的设计本身就是为了能够在当前线程中有属于自己的变量,并不是为了解决并发或者共享变量的问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thecoastlines

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值