共计 1228 个字符,预计需要花费 4 分钟才能阅读完成。
大家好,这里是 淇妙小屋 ,一个分享技术,分享生存的博主
以下是我的主页,各个主页同步更新优质博客,创作不易,还请大家点波关注
掘金主页
知乎主页
Segmentfault 主页
开源中国主页
后续会公布更多 MySQL,Redis,并发,JVM,分布式等面试热点常识,以及 Java 学习路线,面试重点,职业规划,面经等相干博客
转载请表明出处!
0. 类图和 get()办法调用图
1. 类关系
- 每个 Thread 都有一个 ThreadLocalMap,ThreadLocalMap 中存储着多个 Entry 对象,这些 Entry 对象就是该线程独有的变量正本
- 每个 Entry 都能够绑定一个 ThreadLocal 实例(ThreadLocal 是 key,Entry 是 value)
ThreadLocalMap中的 Entry[]table能够了解为一个键值对,key 为 ThreadLocal 实例,value 为 Entry 对象(示意线程在这个 ThreadLocal 实例上绑定的变量正本),table 采纳凋谢地址法解决抵触
2. 一个线程调用 ThreadLocal.get()
有以下三种状况
线程的 ThreadLocalMap 未初始化,为空
绿色执行门路
线程的 ThreadLocalMap 已初始化,然而该 ThreadLocal 实例对应的索引上不存在 Entry
蓝色执行门路
线程的 ThreadLocalMap 已初始化,并且该 ThreadLocal 实例对应的索引上存在 Entry
红色执行门路
3. 线程调用 ThreadLocal.set()
根本逻辑同 get()
4. ThreadLocal 内存透露和 Entry 革除
4.1 弱援用防止 ThreadLocal 内存透露
Entry 继承自 WeakReference,留神 Entry 不是弱援用,Entry 中的 reference 才是弱援用,这个弱援用防止了 ThreadLocal 的内存透露
咱们个别应用线程池,线程的生命周期很长,所以 Thread 援用会存在很长一段时间
如果咱们不应用 ThreadLocal 了,将 ThreadLocal 援用设置为 null(或者办法执行结束,ThreadLocal 援用弹出栈)
没有了 ThreadLocal 援用,ThreadLocal 无奈被拜访到,线程就无奈应用 ThreadLocal,此时 GC 应该要回收掉 ThreadLocal 对象
若 Entry 的援用是强援用,会导致 ThreadLocal 无奈被回收,造成内存透露
所以 Entry 的援用必须是弱援用,这样一旦产生 GC,ThreadLocal 就会被回收
4.2 Entry 革除
ThreadLocal 一旦被回收,那么 Entry 对象的 reference 就为空,此时 Entry 也是无用的,应该被回收掉——expungeStaleEntry()会回收掉那么 reference 为 null 的 Entry 对象 (详情看源代码或者 0. 类图和 get() 办法调用图)
许多个中央都会调用 expungeStaleEntry() 来革除无用的 Entry,例如 get()和扩容