SpringBootWeb 篇-深入了解 ThreadLocal 存在内存泄漏问题

🔥博客主页: 【小扳_-CSDN博客】**
❤感谢大家点赞👍收藏⭐评论✍**

文章目录

[1.ThreadLocal 概述](#1.ThreadLocal 概述)

[2.ThreadLocal 的主要缺点:](#2.ThreadLocal 的主要缺点:)

[2.1 存在内存泄漏](#2.1 存在内存泄漏)

[2.2 为什么ThreadLocalMap 的 key 是弱引用?](#2.2 为什么ThreadLocalMap 的 key 是弱引用?)

[](#2.3 采用线性探测方法)[2.3 采用线性探测方法](#2.3 采用线性探测方法)

[](#3. 不使用线程池会出现内存泄漏吗?)[3. 不使用线程池会出现内存泄漏吗?](#3. 不使用线程池会出现内存泄漏吗?)


1.ThreadLocal 概述

ThreadLocal 是每一个线程都独立拥有的,是线程隔离的。且每个线程只能访问自己的 ThreadLocalMap,是一个 key - value 结构,key 代表着 threadLocal 对象,而 value 代表着对应设置的值。因此,每一个线程中只有一个 ThreadLocalMap,ThreadLocalMap 中可以存放着多个 threadLoal 对象和对应着 value 值,即 key - value 结构。

2.ThreadLocal 的主要缺点:

2.1 存在内存泄漏

在线程池技术下,使用 ThreadLocal 会出现内存泄漏问题。因为,当线程执行完毕之后,引用着 threadLocal 对象的成员变量会直接出栈,这时候,对于这个 threadLocal 对象就没有变量对其进行操作了,会一直存在,且没有办法使用,这就是内存泄漏。

即使当前引用 threadLocal 对象是一个静态变量,可能会一直引用着这个 threadLocal 对象。但是类加载器是可以被卸载的,同样的,这个 threadLocal 对象也会没有变量对其进行操作。

2.2 为什么ThreadLocalMap 的 key 是弱引用?

是为了减少内存泄漏。当出现没有栈中没有变量继续引用 threadLocal 对象时,且执行 gc 的时候,因为 key 是弱引用,会被置为 null,在 ThreadLocal 每次 get 或者是 set 的时候会对 Entry 进行一个清空 key 为 null 的操作,当发现出现 key 为 null 的时候,会对 value 也置为 null,同时将这个 key - value 从 threadLocalMap 中进行移除操作。但是这个清除 Entry 操作不是每次从头开始,因此还是会出现内存泄漏的风险。

避免使用 ThreadLocal 出现内存泄漏,应该在使用完之后,进行 remove 操作!

2.3 采用线性探测方法

当 ThreadLocalMap 存储一个 threadLocal 对象的时候,采用的是线性探测方法,当遇到 Hash 冲突的时候,性能不高。提高性能的方法可以采取链地址法。

代码演示:

java 复制代码
public class Example {
    private static final ThreadLocal<User> userThreadLocal = new ThreadLocal<>();

    public void process() {
        try {
            User user = getUserFromRequest();
            userThreadLocal.set(user);
            // 业务逻辑
        } finally {
            userThreadLocal.remove(); // 确保清理
        }
    }
}

3. 不使用线程池会出现内存泄漏吗?

如果线程是 普通线程(非线程池中的线程),且任务执行完毕后线程 正常结束(如 run() 方法执行完毕或调用 interrupt()),则:线程对象会被销毁,其内部的 ThreadLocalMap 也会被垃圾回收器回收。无需显式调用 remove(),因为线程结束后,ThreadLocalMap 及其存储的值会自动被释放。

ThreadLocalMap 是线程的一部分,当线程结束时,整个 ThreadLocalMap 都会被回收,这样即使没有调用 remove(),也不会有泄漏。其次,如果线程没有正确结束,比如长时间运行的守护线程,或者主线程一直运行,这时候可能会有问题。但这种情况比较少见,通常主线程结束程序就会退出了。

还需要提到静态的 ThreadLocal 实例,如果声明为 static,即使线程结束,ThreadLocal 对象可能不会被回收,但如果是非静态的,随着线程结束,ThreadLocal 对象也会被回收。不过,如果线程没有结束,比如某些情况下线程被长时间持有,比如服务器中的工作线程,这时候即使不使用线程池,也可能导致泄漏。

相关推荐
uzong4 小时前
一个好的面试官,应该让候选人感到被尊重
面试
咩咩啃树皮5 小时前
第40篇:Vue3组件化开发精讲——组件拆分、复用、父子通信、工程化架构
java·前端·架构
灯澜忆梦5 小时前
GO_并发编程---定时器
开发语言·后端·golang
鱟鲥鳚6 小时前
Spring Boot 集成 LangChain4j:从模型调用到 Tool Calling(Demo版)
java·spring boot
-银雾鸢尾-6 小时前
C#中的StringBuilder相关方法
开发语言·c#
-银雾鸢尾-6 小时前
C#中结构体与类的区别;抽象类与接口的区别
开发语言·c#
触底反弹7 小时前
深入理解大模型采样:Temperature、Top-K、Top-P 的原理与实战
人工智能·算法·面试
大模型码小白7 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
腾渊信息科技公司8 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
沉默王二9 小时前
腾讯一面,我霸气反问:“你说你们在做Agent项目,说说 SubAgent、Plan 模式、Skill 调用这些你们都是怎么做的?”面试官一直在擦汗。。
面试·agent·ai编程