原文: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开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞+转发哦!