java源码阅读之深入理解ThreadLocal
2019-03-31 17:34
573 查看
总结:
- 每一个Thread实例中都会保存一个map数据结构,map中的Entry<ThreadLocal,value>用来存储线程中用到的每个ThreadLocal的引用和其对应的value。使用set和get方法时,在Thread实例的map中查找和修改ThreadLocal对应的value值。
- 防止内存泄露问题:因为map中的Entry对象存储的是ThreadLocal的弱引用,所以在gc时ThreadLocal有可能被回收,之后其对应的Entry<ThreadLocal, value>中的ThreadLocal就为null,但是Entry却由于存在强引用而不能被回收。所以在使用get和set
方法时,如果遇见了ThreadLocal == null的Entry直接将其删除。很多情况下需要使用者手动调用ThreadLocal的remove函数,手动删除不再需要的ThreadLocal来防止内存泄露。因此JDK建议将ThreadLocal变量定义成private static的,这样的话ThreadLocal的生命周期就更长,由于一直存在ThreadLocal的强引用,所以ThreadLocal也就不会被回收,也就能保证任何时候都能根据ThreadLocal的弱引用访问到Entry的value值,然后remove它,防止内存泄露。
先看简介
ThreadLocals rely on per-thread linear-probe hash maps attached to each thread (Thread.threadLocals and inheritableThreadLocals). The ThreadLocal objects act as keys, searched via threadLocalHashCode.
- ThreadLocal们依赖关联到每个线程上的哈希表。其中以ThreadLocal对象为key,通过threadLocalHashCode来搜索。
从初始化函数切入
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { map.set(this, value); } else { createMap(t, value); } if (this instanceof TerminatingThreadLocal) { TerminatingThreadLocal.register((TerminatingThreadLocal<?>) this); } return value; }
- 我们可以看到使用了ThreadLocalMap这个对象,其为ThreadLocal的内部静态类,阅读后得知其中有Entry类为弱引用(防止垃圾回收无法回收Entry对象)
static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
- 继续阅读初始化函数,通过getMap获取map对象
ThreadLocal.ThreadLocalMap threadLocals = null;
- 每一个Thread对象都保存了一个map用来保存ThreadLocal和value副本,如果map为null则在Thread的map中添加一个新的Entry对象(稍后会解释)
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
- 注意:创建map中新的Entry<key,value>对象的key不是Thread实例的hashcode而是ThreadLocalHashCode
- 这样每个Thread通过维持一个map数据结构就拥有其所有的ThreadLocal中的变量副本了
Set方法
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { map.set(this, value); } else { createMap(t, value); } }
- 依旧从Thread实例中获取map,如果没有该变量则在map中新建一个Entry<ThreadLocalHashCode, value>,如果有的话就修改
get方法
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
- 如果map不为空则获取LocalThreadMap中的Entry对象,以ThreadLocalHashCode在map中匹配value,如果map为空则重新进行初始化
相关文章推荐
- java源码阅读之深入理解AQS
- 深入源码理解-java动态代理
- 深入理解Java 虚拟机阅读笔记(一)
- Java 并发:深入理解 ThreadLocal
- 深入理解JAVA集合系列四:ArrayList源码解读
- 深入理解java虚拟机阅读笔记四:java代码编译和执行过程
- java jdbc深入理解(connection与threadlocal与数据库连接池和事务实)
- 深入理解Java虚拟机JVM高级特性与最佳实践阅读总结——第三章垃圾收集器与内存分配策略
- 深入理解Java虚拟机JVM高级特性与最佳实践阅读总结—— 第七章 虚拟机类加载机制
- Java 并发:深入理解 ThreadLocal
- Java 集合深入理解(16):HashMap 主要特点和关键方法源码解读
- java 集合类深入理解 - ArrayList 源码解析
- 深入理解Java虚拟机JVM高级特性与最佳实践阅读总结—— 第十二章 Java内存模型与线程
- java 集合类深入理解 - HashMap 源码解析
- Java程序员从笨鸟到菜鸟之(八十二)细谈Spring(十一)深入理解spring+struts2整合(附源码)
- Java程序员从笨鸟到菜鸟之(八十二)细谈Spring(十一)深入理解spring+struts2整合(附源码)
- 深入理解Java虚拟机JVM高级特性与最佳实践阅读总结——第二章 Java内存区域与内存溢出异常
- 深入理解JAVA集合系列四:ArrayList源码解读
- Java中的ThreadLocal深入理解
- 深入学习理解java-ThreadLocal