问二十七:ThreadLocal源码解析

ThreadLocal概述:

ThreadLocal是一个本地线程副本变量工具类,运用到了线程封闭技术

用来维护线程中的变量不被其他线程干扰而出现的一个结构,内部包含一个ThreadLocalMap类(该类由一个继承自虚引用的Entry来存具体的值,需要留意还有一个用来存Entry的table数组),该类为Thread类的一个实例属性(非static的成员变量),该Entry存储的key为ThreadLocal对象自身,value为我们要存储的值或对象。

这样一来,在不同线程中,持有的其实都是当前线程的变量副本,与其他线程完全隔离,以此来保证线程执行过程中不受其他线程的影响。

 

ThreadLocal使用流程:

使用时可以重写initialValue()方法,当线程进行get调用时,获取当前线程对象实例的threadLocals这个成员变量。

它的类型为ThreadLocal.ThreadLocalMap,内部是一个继承了WeakReference<ThreadLocal<?>>的Entry,可以存当前ThreadLocal引用和对应的值。

获取之后进行一个是否为null的判断,Thread类中默认为null,写入或者更新通过initialValue()确定的值。

当线程需要取出线程本地变量的时候,还是从Thread实例对象中取出之前赋好值的threadLocals,再从ThreadLocalMap.Entry中取出实际对应的值。

因此ThreadLocal实际上是不存值的,只是起到存入或取出线程实例中ThreadLocalMap中线程对应值的功能。

只要线程处于活跃状态(alive)并且ThreadLocal实例可以访问,那么每个线程都会持有着一个线程本地变量副本的隐式副本。

线程消失之后,线程本地实例的所有相关副本都会进行垃圾回收(除非存在对这些副本的其他引用)

注:因此虽然ThreadLocal它的底层存储结构(ThreadLocalMap)是弱引用(Entry extends WeakReference<java.ThreadLocal<?>>),但是并不是这个弱引用的值一被置为null就会被回收,因为存活着的那个线程对它还有一个强引用  (ThreadLocal.ThreadLocalMap threadLocals = Entry(ThreadLocal<?> k, null);)

源代码解析:ThreadLocal

 

内存泄露问题:

会引发内存泄露↓

问二十七:ThreadLocal源码解析

问二十七:ThreadLocal源码解析

 

问二十七:ThreadLocal源码解析


通过调用remove()方法避免内存溢出

问二十七:ThreadLocal源码解析

问二十七:ThreadLocal源码解析

 

实际运用场景:

如果用SimpleDateFormat对象转换日期格式,但是不想每次请求创建新的SimpleDateForma对象,为了可以解决并发场景下的性能问题可以使用到ThreadLocal