原文:blog.csdn.net/qunqunstyle99/article/details/94717256
ThreadLocal 是什么
ThreadLocal 是一个本地线程正本变量工具类。次要用于将公有线程和该线程寄存的正本对象做一个映射,各个线程之间的变量互不烦扰,在高并发场景下,能够实现无状态的调用,特地实用于各个线程依赖不通的变量值实现操作的场景。
下图为 ThreadLocal 的外部结构图
从下面的结构图,咱们曾经窥见 ThreadLocal 的外围机制:
- 每个 Thread 线程外部都有一个 Map。
- Map 外面存储线程本地对象(key)和线程的变量正本(value)
- 然而,Thread 外部的 Map 是由 ThreadLocal 保护的,由 ThreadLocal 负责向 map 获取和设置线程的变量值。
所以对于不同的线程,每次获取正本值时,别的线程并不能获取到以后线程的正本值,造成了正本的隔离,互不烦扰。
举荐一个开源收费的 Spring Boot 最全教程:
https://github.com/javastacks/spring-boot-best-practice
ThreadLocalMap
ThreadLocalMap 是 ThreadLocal 的外部类,没有实现 Map 接口,用独立的形式实现了 Map 的性能,其外部的 Entry 也独立实现。
和 HashMap 的最大的不同在于,ThreadLocalMap 构造非常简单,没有 next 援用,也就是说 ThreadLocalMap 中解决 Hash 抵触的形式并非链表的形式,而是采纳线性探测的形式。(ThreadLocalMap 如何解决抵触?)
在 ThreadLocalMap 中,也是用 Entry 来保留 K - V 构造数据的。然而 Entry 中 key 只能是 ThreadLocal 对象,这点被 Entry 的构造方法曾经限定死了。
static class Entry extends WeakReference<ThreadLocal> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal k, Object v) {super(k);
value = v;
}
}
留神了!!
Entry 继承自 WeakReference(弱援用,生命周期只能存活到下次 GC 前),但只有 Key 是弱援用类型的,Value 并非弱援用。(问题马上就来了)
因为 ThreadLocalMap 的 key 是弱援用,而 Value 是强援用。这就导致了一个问题,ThreadLocal 在没有内部对象强援用时,产生 GC 时弱援用 Key 会被回收,而 Value 不会回收。
当线程没有完结,然而 ThreadLocal 曾经被回收,则可能导致线程中存在 ThreadLocalMap<null, Object>
的键值对,造成内存泄露。(ThreadLocal 被回收,ThreadLocal 关联的线程共享变量还存在)。
如何防止透露
为了避免此类情况的呈现,咱们有两种伎俩。
1、应用完线程共享变量后,显示调用 ThreadLocalMap.remove
办法革除线程共享变量;
既然 Key 是弱援用,那么咱们要做的事,就是在调用 ThreadLocal 的 get()
、set()
办法时实现后再调用 remove 办法,将 Entry 节点和 Map 的援用关系移除,这样整个 Entry 对象在 GC Roots 剖析后就变成不可达了,下次 GC 的时候就能够被回收。
2、JDK 倡议 ThreadLocal 定义为private static
,这样 ThreadLocal 的弱援用问题则不存在了。
文章参考:
- www.jianshu.com/p/98b68c97df9b
- www.cnblogs.com/coshaho/p/5127135.html
近期热文举荐:
1.1,000+ 道 Java 面试题及答案整顿(2022 最新版)
2. 劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4. 别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!
5.《Java 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!