专业网站建设品牌,十四年专业建站经验,服务6000+客户--广州京杭网络
免费热线:400-683-0016      微信咨询  |  联系我们

如何去理解ThreadLocal_java

当前位置:网站建设 > 技术支持
资料来源:网络整理       时间:2023/3/7 1:03:00       共计:3587 浏览

如何去理解ThreadLocal?

ThreadLocal是什么?

ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不通的变量值完成操作的场景.

ThreadLocal特点:就是在一个线程里放一个数据,不管中间执行了什么操作。只要想获取出来的时候,调用get就可以得到保存进去的数据.

ThreadLocal内部结构图

从上面的结构图中,我们可以看到ThreadLocal的核心机制

每个Thread 内部都有一个Map。Map里面存储线程本地对象(key) 和线程的变量副本(value)。Thread 内部的Map是由 ThreadLocal为的,由ThreadLocal负责向map获取和设置线程的变量值。

Thread线程内部的Map在类中描述如下:

ThreadLocal 为什么会内存泄漏

我们先分析一下ThreadLocalMap

我们可以知道每个Thread 维护一个 ThreadLocalMap,这个映射表的 key 是 ThreadLocal实例本身,value 是真正需要存储的 Object,也就是说 ThreadLocal 本身并不存储值,它只是作为一个 key 来让线程从 ThreadLocalMap 获取 value。仔细观察ThreadLocalMap,这个map是使用 ThreadLocal 的弱引用作为 Key 的,弱引用的对象在 GC 时会被回收。

这样,当把threadlocal变量置为null以后,没有任何强引用指向threadlocal实例,所以threadlocal将会被gc回收。这样一来,ThreadLocalMap中就会出现key为null的Entry,就没有办法访问这些key为null的Entry的value,如果当前线程再迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value,而这块value永远不会被访问到了,所以存在着内存泄露。

其实java 开发者,也考虑到了此问题,所以在get(),set()的时候,调用了expungeStaleEntry方法用来清除Entry中Key为null的Value,但是这是不及时的,也不是每次都会执行的,所以一些情况下还是会发生内存泄露。只有remove()方法中显式调用了expungeStaleEntry方法。

下面看下ThreadLocal 的get()方法的实现:

下面继续看 map.getEntry方法

当key 为null 时,调用getEntryAfterMiss方法

当key 为null 时,调用expungeStaleEntry 方法

也许有人会好奇,有上面方法,为什么还会导致内存泄漏呢?

一般我们设置的ThreadLocal设置为static的,static 变量可以作为GCRoot的根节点,所以会一直存在初始化了ThreadLocal, 调用set ,get 而没有调用remove方法,所以会导致内存泄漏。

比如get方法,只有ThreadLocalMap中没有所需要的key时,才会调用清除方法

版权说明:
本网站凡注明“广州京杭 原创”的皆为本站原创文章,如需转载请注明出处!
本网转载皆注明出处,遵循行业规范,如发现作品内容版权或其它问题的,请与我们联系处理!
欢迎扫描右侧微信二维码与我们联系。
·上一条:你身边有哪些人最终成为了Java架构师_java | ·下一条:eclipse怎么用gradle_java

Copyright © 广州京杭网络科技有限公司 2005-2024 版权所有    粤ICP备16019765号 

广州京杭网络科技有限公司 版权所有