ThreadLocal 会出现内存泄漏吗?

ThreadLocal

ThreadLocal 是一个用来解决线程安全性问题的工具。它相当于让每个线程都开辟一块内存空间,用来存储共享变量的副本。然后每个线程只需要访问和操作自己的共享变量副本即可,从而避免多线程竞争同一个共享资源。它的工作原理很简单(如图)每个线程里面有一个成员变量ThreadLocalMap。当线程访问用 ThreadLocal 修饰的共享数据的时候这个线程就会在自己成员变量 ThreadLocalMap 里面保存一份数据副本。key 指向 ThreadLocal 这个引用,并且是弱引用关系,而 value 保存的是共享数据的副本。因为每个线程都持有一个副本,所以就解决了线程安全性问题。

内存泄漏

ThreadLocal 中的引用关系如图所示(如图),Thread 中的成员变量 ThreadLocalMap,它里面的可以 key 指向 ThreadLocal 这个成员变量,并且它是一个弱引用所谓弱引用,就是说成员变量ThreadLocal 允许在这种引用关系存在的情况下,被 GC回收。一旦被回收,key 的引用就变成了 null,就会导致这个内存永远无法被访问,造成内存泄漏。

总结

不恰当的使用 ThreadLocal,会造成内存泄漏问题。主要原因是,线程的私有变量ThreadLocalMap 里面的 key 是一个弱引用。弱引用的特性,就是不管是否存在直接引用关系, 当成员 ThreadLocal 没用其他的强引用关系的时候,这个对象会被 GC 回收掉。从而导致 key 可能变成 null,造成这块内存永远无法访问,出现内存泄漏的问题。规避内存泄漏的方法有两个:

  • 通过扩大成员变量 ThreadLoca 的作用域,避免被 GC 回收
  • 每次使用完 ThreadLocal 以后,调用 remove 方法移除对应的数据

第一种方法虽然不会造成key为null的现象,但是如果后续线程不再继续访问这个key。也会导致这个内存一直占用不释放,最后造成内存溢出的问题。所以我认为最好是在使用完以后调用 remove 方法移除。

java 复制代码
public class ThreadLocalExample {
    private static ThreadLocal<Integer> myThreadLocal = new ThreadLocal<>();

    public static void main(String[] args) {
        // 创建两个线程,并为每个线程设置不同的值
        Thread thread1 = new Thread(() -> {
            myThreadLocal.set(10);
            System.out.println("Thread 1: " + myThreadLocal.get());
            myThreadLocal.remove(); // 清除线程本地变量的值
        });

        Thread thread2 = new Thread(() -> {
            myThreadLocal.set(20);
            System.out.println("Thread 2: " + myThreadLocal.get());
            myThreadLocal.remove(); // 清除线程本地变量的值
        });

        thread1.start();
        thread2.start();
    }
}
相关推荐
代衡_Monster9 分钟前
通过位运算实现Java逻辑的包含关系
java·java-ee
毕设源码-朱学姐9 分钟前
【开题答辩全过程】以 基于Java的失物招领系统设计与实现为例,包含答辩的问题和答案
java·开发语言
Gomiko12 分钟前
JavaScript进阶(四):DOM监听
开发语言·javascript·ecmascript
清晓粼溪14 分钟前
统一异常处理
java·开发语言
TH_134 分钟前
4、前台界面,表格列名写错
java
syt_101341 分钟前
grid布局之-子项放置4
开发语言·javascript·ecmascript
喵了meme43 分钟前
C语言实战2
c语言·开发语言·网络
charlie1145141911 小时前
现代C++工程实践:简单的IniParser3——改进我们的split
开发语言·c++·笔记·学习
fish_xk1 小时前
c++的引用和类的初见
开发语言·c++
没有bug.的程序员1 小时前
高频IO服务优化实战指南
java·jvm·spring·容器