多线程数据隔离原来这么简单

首先我们来看一下这个

猜猜输出的是什么?结果一样吗?

好了我们看

结果不一样。为什么呢?

我们现在一个类Thread类,发现Thread中维护了一个ThreadLocal.ThreadLocalMap类型的字段,换言之,只要创建了不同的线程那么就会存在多个ThreadLocalMap即不同的线程维护了不同的变量副本

回头来看看我们在使用ThreadLocal实例变量调用其set方法时的源码如下

调用set方法的时候,会获取当前线程对象 ,然后从获取到的线程对象实例中拿到对应的ThreadLocalMap,将当前实例对象(调用set方法的ThreadLocal实例)作为ThreadLocalMap的key,传入的值作为ThreadLocalMap的value存入线程变量副本(map)中,那么就会有以下几种情况:

1.当存在多个线程时,即存在多个ThreadLocalMap(线程变量副本),即使是同一个ThreadLocal实例,即ThreadLocalMap的this是同一个,那也不会产生数据覆盖,因为ThreadLocalMap不是同一个,好比将同一瓶水放入不同的水杯

2.在一个线程内,创建多个ThreadLocal实例,也不会产生数据覆盖问题,虽然ThreadLocalMap是同一个但map中的key不同

​​​​

总结一下就是不同的线程,拿到ThreadLocal.ThreadLocalMap类型的threadLocals字段不一样,获取ThreadLocalMap也就不一样。

即使是同一个ThreadLocal对象的实例去调set方法,出来的结果也就不会被覆盖。

同理,如果同一个线程内,但是ThreadLocal对象的实例不同,那么结果也不会覆盖

ThreadLocalMap里面是一个又一个的Entry,Entry里面是一个key-value结构,Entry里面的key和value就是set方法里的this和value,

同时Entry由于继承了WeakReference这个类,所以Entry是弱引用对象

Entry是弱引用对象,当ThreadLocal对象的实例,就是set方法里的this没有被引用,也就是Entry里的key,就会被gc回收。但是刚才说了Entry它是放在ThreadLocalMap里面的(ThreadLocalMap和Entry是强引用),ThreadLocalMap它是在线程里的,线程不结束,即使Entry的key被回收了,它也依然存在,也就是它里面的value依旧存在。

随着程序的运行,久了之后可能ThreadLocalMap的值会越来越多就会出现内存泄漏的问题,怎么解决呢?

就是在使用完线程共享变量后,显式调用ThreadLocalMap.remove方法清除线程共享变量,这样就是手动切断ThreadLocalMap与Entry之间的引用关系,然后就可以被回收了

图例:

当存储一个键值对后,ThreadLocalMap的key是ThreadLocal对象,value是存储的变量,他们通过Entry弱引用关联

当我们不使用ThreadLocal对象的时候,threadlocal=null;由于是弱引用,那么在垃圾回收后,ThreadLocal对象可以被回收 。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值