ThreadLocal
1.1基础介绍
ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不通的变量值完成操作的场景。 用一句精炼的话来概括ThreadLocal的作用:ThreadLocal用于线程间的数据隔离。
1.2原理
ThreadLocal的原理:在每一个Thread中都管理着一个Map,其中存储着线程本地对象(key)和线程的副本变量(value)。通过ThreadLocal获取和设置线程中的Map来维护副本变量。 所以当线程要获取副本变量时不会取到其他线程的副本变量。
1.3核心方法
ThreadLocal有以下四个核心方法: (1)initialValue()为当前线程初始副本变量值。 (2)set()方法用于保存当前线程的副本变量值。 (3)get()方法用于获取当前线程的副本变量值。 (4)remove()方法移除当前前程的副本变量值。
注意:get、set、remove方法都是先获取当前线程中map threadLocals属性。而ThreadLocal本身并没有承担存储每个线程中的数据的职责,它是通过操作每个线程内部的一个“副本”-ThreadLocalMap来实现线程之间的隔离,从而保证了线程安全。
1.4ThreadLocal内存泄漏问题
问题:
从源码中我们可以看到ThreadLocalMap是ThreadLocal的一个内部类,并且map键值对中的key是一个弱引用。因此如果ThreadLocal没有外部强引用来引用它,那么ThreadLocal会在下次JVM垃圾收集时被回收。这个时候就会出现Entry中Key已经被回收,出现一个null Key的情况,外部读取ThreadLocalMap中的元素是无法通过null Key来找到Value的。而当线程的生命周期很长时,就有可能导致内存泄漏。
解决方式:
避免内存泄漏的方法: 在使用完ThreadLocal的get、set方法之后调用remove方法,把Entry和map的引用关系删除,这样在JVM垃圾清除的过程中,Entry和map没有引用关系,就会被JVM整个清除掉,不会导致内存泄漏。