我们都知道treadlocal维护变量时候,可以为每个线程维护一个独立的副本,改变的是自己线程的数据。
ThreadLocal公用方法有四个:get,set,remove,intiValue
既然threadLocalMap是局部变量,所以他存在Thread里面,并不是在TheradLocal。
所以存储map的是图里的threadLocals
而theradLocals的对象是ThreadLocal.ThreadLocalMap,它是TheradLocal静态内部类。
他们的关系是什么呢?
一个thread只有一个threadLocalMap,一个threadLocalMap中分别存放着3个Entry,默认一个threadLocalMap初始化16个Entry,每个Entry存放一个ThreadLocal变量对象。
一、ThreadLocal的SET方法
这里的TreadLocal进行了两层包装,第一是弱引用WeakReference
第二是Entry继承
(WeakReference与强引用不同,弱引用会随着GC的时候被回收)
ThreadLocalMap构造函数,初始化Entry大小是16。
数组索引的取值方式是 用 线程安全的 AtomicInteger nextHashCode,与
&(INTITAL_CAPACITY-1)。
根据线程来,每个线程都有一个ThreadLocalMap,为空则创建新的ThreadLocalMap,不为空则放入当前ThreadLocal。
二、ThreadLocal的GET方法
get方法首先是通过thread获取threadLocalMap对象,
这时候传入this表示当前threadlocal找到对应的entry
如果为null则调用getEntryAfterMiss方法
此方法表示hash散列没找到,则顺着hash表递增循环往下找,一直到出现空为止。
- ThreadLocal内存回收
- 当线程死亡的时候,所有线程局部变量都会回收,这时候threadLocalMap会被回收
- 如果线程存活的时间很长,里面的entry对象会越来越多,这时候就需要清理了,在set方法里面,clearSomeSlots方法就是回收内存,当大于2/3时候,会清理。
当我们使用线程池的时候,意味着当前线程未必会退出(比如固定大小线程池,线程总是存在),这时候如果threadLocal中对象太大,就会内存溢出。
当使用线程池固定线程,多个线程放多个大对象在map里面,但因为线程一直存在不会被销毁,导致内存溢出。所以正常情况下内存不会溢出,但是多线程的情况下要小心。