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 对象也会被回收。不过,如果线程没有结束,比如某些情况下线程被长时间持有,比如服务器中的工作线程,这时候即使不使用线程池,也可能导致泄漏。

相关推荐
magic334165639 小时前
Springboot整合MinIO文件服务(windows版本)
windows·spring boot·后端·minio·文件对象存储
锦***林10 小时前
用 Python 写一个自动化办公小助手
开发语言·python·自动化
陈小桔10 小时前
idea中重新加载所有maven项目失败,但maven compile成功
java·maven
小学鸡!10 小时前
Spring Boot实现日志链路追踪
java·spring boot·后端
xiaogg367810 小时前
阿里云k8s1.33部署yaml和dockerfile配置文件
java·linux·kubernetes
逆光的July10 小时前
Hikari连接池
java
微风粼粼11 小时前
eclipse 导入javaweb项目,以及配置教程(傻瓜式教学)
java·ide·eclipse
番茄Salad11 小时前
Spring Boot临时解决循环依赖注入问题
java·spring boot·spring cloud
立志成为大牛的小牛11 小时前
数据结构——二十六、邻接表(王道408)
开发语言·数据结构·c++·学习·程序人生
天若有情67311 小时前
Spring MVC文件上传与下载全面详解:从原理到实战
java·spring·mvc·springmvc·javaee·multipart