原文: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开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞+转发哦!