ThreadLocal
标签: 后端
upupor   120   0 2020-08-03 01:46 
最新一次编辑的原因:

ThreadLocal的主要作用是数据隔离,填充的数据只属于当前线程,变量的数据对别的线程而言是相对隔离的。

隔离的场景:

  • Spring事务隔离级别。Spring采用Threadlocal的方式,来保证单个线程中的数据库操作使用的是同一个数据库连接,同时,采用这种方式可以使业务层使用事务时不需要感知并管理connection对象,通过传播级别,巧妙地管理多个事务配置之间的切换,挂起和恢复。
  • 自己生产环境中使用的场景。大数据业务研发框架,处理数据清洗环节中的任务对象、链接对象等等
  • 多数据源切换,多站点,多数据源
  • 很多场景的cookie,session等数据隔离都是通过ThreadLocal去做实现的。

ThreadLocal的原理:

  • 先说下基本的使用方法
  • ThreadLocalMap ——> ThreadLocal数据隔离的真相了,每个线程Thread都维护了自己的threadLocals变量,所以在每个线程创建ThreadLocal的时候,实际上数据是存在自己线程Thread的threadLocals变量里面的,别人没办法拿到,从而实现了隔离。
  • ThreadLocalMap底层结构。ThreadLocalMap的Entry是继承WeakReference(弱引用)的,也没有看到HashMap中的next,所以不存在链表了。

为什么需要数组呢?没有了链表怎么解决Hash冲突呢?

用数组是因为,我们开发过程中可以一个线程可以有多个ThreadLocal来存放不同类型的对象的(解释:比如在线程A中包含 ThreadLocal userA, ThreadLocal userB 等多个),但是他们都将放到你当前线程的ThreadLocalMap里,所以肯定要数组来存。

能跟我说一下对象存放在哪里么?

在Java中,栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存,而堆内存中的对象对所有线程可见,堆内存中的对象可以被所有线程访问。

那么是不是说ThreadLocal的实例以及其值存放在栈上呢?

其实不是的,因为ThreadLocal实例实际上也是被其创建的类持有(更顶端应该是被线程持有),而ThreadLocal的值其实也是被线程实例持有,它们都是位于堆上,只是通过一些技巧将可见性修改成了线程可见。

如果我想共享线程的ThreadLocal数据怎么办?

使用InheritableThreadLocal可以实现多个线程访问ThreadLocal的值,我们在主线程中创建一个InheritableThreadLocal的实例,然后在子线程中得到这个InheritableThreadLocal实例设置的值。

数据共享的值是怎么传递的?

ThreadLocal使用过程中有哪些问题?

内存泄露

为什么会有内存泄漏的问题?

ThreadLocal在保存的时候会把自己当做Key存在ThreadLocalMap中,正常情况应该是key和value都应该被外界强引用才对,但是现在key被设计成WeakReference弱引用了。

弱引用:

只具有弱引用的对象拥有更短暂的生命周期,在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存

不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

这就导致了一个问题,ThreadLocal在没有外部强引用时,发生GC时会被回收,如果创建ThreadLocal的线程一直持续运行,那么这个Entry对象中的value就有可能一直得不到回收,发生内存泄露。

就比如线程池里面的线程,线程都是复用的,那么之前的线程实例处理完之后,出于复用的目的线程依然存活,所以,ThreadLocal设定的value值被持有,导致内存泄露。

按照道理一个线程使用完,ThreadLocalMap是应该要被清空的,但是现在线程被复用了。

怎么解决ThreadLocal的内存泄漏问题呢?

在代码的最后使用remove就好了,我们只要记得在使用的最后用remove把值清空就好了。remove的源码很简单,找到对应的值全部置空,这样在垃圾回收器回收的时候,会自动把他们回收掉。

为什么ThreadLocalMap的key要设计成弱引用?

key不设置成弱引用的话就会造成和entry中value一样内存泄漏的场景。


本作品系原创,采用《署名-非商业性使用-禁止演绎4.0 国际》许可协议.转载请说明出处
本文链接:https://www.upupor.com/u/20080301462851294208 复制分享

无评论内容,快来评论吧