ThreadLocal详解

一、什么是ThreadLocal?

它是一个数据结构,主要用于存储线程内的局部变量的。每个线程都有自己的局部变量,在多线程环境下访问时,能保证各个线程的变量能够独立于其他线程内变量之外。ThreadLocal实例通常是private static来修饰,它们希望将状态与各个线程相关联。其存储结构是ThreadLocalMap,其底层是entry数组,以键值对的形式存放,键是ThreadLocal对象,value是set()设置的值。当执行set方法时,其value是保存在threadlocals变量中的,当执行get方法时,就是读取threadlocals变量中的值。总之就是,各个线程的数据互不打扰。一个线程可以存放多个ThreadLocal变量,他们都是存在了ThreadLocalMap中,网上说的一个ThreadLocal只能存放一个键值对的意思,应该是值ThreadLocal对象,它是唯一的。并不是说一个线程里只能有一个。

二、ThreadLocal数据结构图解

ThreadLocal详解_第1张图片

三、set()、get()具体过程

每个ThreadLocal对象都有一个hash值ThreadLocalHashCode,每初始化一个对象,hash值就增加一个固定的大小。在插入的过程中,会先根据ThreadLocal对象的hash值,计算table中对应的索引位置,如果当前位置为空,则直接插入;如果不为空且和key相等的话,就覆盖原来的值;如果不为空且不等,则继续往下找空位置。

get方法就是根据索引值,判断key是否一致,一致则返回value;否则判断下一个。

四、ThreadLocal和synchronized

二者是一个相反的作用。ThreadLocal是为了保证线程之间的隔离性,而synchronized是为了保证可见性。synchronized利用了锁机制,同一时刻只能有一个线程访问,而ThreadLocal是每个线程都有变量的副本,每个线程访问的是不同的对象。

五、ThreadLocal内存泄漏

ThreadLocal详解_第2张图片

内存泄漏的意思是:当JVM进行GC垃圾回收时,因为有强引用的存在,一直无法回收,却一直占着内存。

ThreadLocal中key是弱引用,value是强引用。当用完,进行GC回收时,因为key是弱引用,回收完为null,但是value是强引用,一直无法回收,就造成了内存泄漏。但是假使key是强引用,同样是无法回收。所以不是这里的问题,是ThreadLocal和Thread生命周期相同的问题,所以一定要记得remove()。记得删除旧的entry数组,不然一直会有删除不掉的数据。ThreadLocal也考虑到了这些,执行get()、set()、remove()时,他会判断key的值是否为空,如果为空,就进行清理。 

注意点:

value为啥不搞成弱引用?是因为不清楚这个Value除了map的引用还是否还存在其他引用,如果不存在其他引用,当GC的时候就会直接清理,而此时我们的ThreadLocal还处于使用期间,就会造成Value为null的错误,所以将其设置为强引用。

而为了解决这个强引用的问题,它提供了一种机制就是将KeyNullEntity直接清除。

key为null的条件是:ThreadLocal变量指向null且是弱引用。

如果key为null,ThreadLocal也指向null,如果没有其他ThreadLocal变量触发set/get/remove方法,还是会造成内存泄漏。

你可能感兴趣的:(java)