ThreadLocal 作用

一般创建的每一个变量所有线程均可以访问和修改,为了实现每一个线程有自己独有的变量,ThreadLocal 就可以用来解决这种问题

自己的理解:
相当于在一个类中定义了一个独有的线程 static final,这个线程中存储了独有的变量 和数据,相当于某一个类下的全局变量容器,可以存放一些想要的数据,不论是主线程还是其他线程在 执行过程中访问到的都是相同的内容,一旦修改,那么所有访问到这个线程的内容也都将更改。

但 ThreadLocal 如果使用不当会造成内存泄漏的问题,内存泄漏积攒多了就可能造成内存溢出,从而程序崩溃出错。

内存泄漏

一些已经无用的数据一直存放在内存中,又无法被回收,导致一直有一部分无法使用的数据占据内存的一部分。

内存溢出

当无法继续申请新的内存空间时,就会出现内存溢出,原因可能是有太多的数据都放到了内存中,导致内存已经被占满了,或者是上面内存泄漏的数据太多,之后导致内存空间越来越少。直至内存溢出,无法再申请内存。

ThreadLocal 会发生内存泄漏的前提条件

  1. ThreadLocal 引用被设为null 后面没有 set, get, remove 操作
  2. 线程一直运行不停止(线程池)
  3. 触发垃圾回收(Minor GC或Full GC)

为了避免内存泄漏的使用原则

  1. ThreadLocal 申明为 private static final (private final 使得对象不被其他对象引用和修改 static 使得对象只有程序结束时才被回收)
  2. ThreadLocal 使用后调用 remove 方法,直接移除。

总结:
提供了 get set remove 三个方法,在不必要时需要 使用remove 去除数据,以免造成累计的无用数据太多而且一直占用内存造成内存泄漏,过多时可能会造成内存溢出,不够用。

ThreadLocal 定义示例

public class MyClass {

    private static final ThreadLocal<String> A_THREAD_OF_MINE = new ThreadLocal<>();

    public void test(){
        MyClass.A_THREAD_OF_MINE.set("the first time");
    }
    
    public void clearData(){
        MyClass.A_THREAD_OF_MINE.remove();
    }

}

如果需要在其他类中调用则修改为 public 定义

使用spring 中的ThreadLocal 关键点示例

import org.springframework.core.NamedInheritableThreadLocal;

public class UserInfoHolder {
    private static final ThreadLocal<UserInfo> USER_INFO_HOLDER = new NamedInheritableThreadLocal<>("myThreadLocal1");

// ...........

}