
文章插图
4.1 ThreadLocalMap源码
static class ThreadLocalMap {// Entry对象 , WeakReference是弱引用 , 当没有引用指向时 , 会被GC回收static class Entry extends WeakReference<ThreadLocal<?>> {// ThreadLocal泛型对象值Object value;// 构造方法 , 传参是key-value// key是ThreadLocal对象实例 , value是ThreadLocal泛型对象值Entry(ThreadLocal<?> k, Object v) {super(k);value = https://www.huyubaike.com/biancheng/v;}}// Entry数组 , 用来存储ThreadLocal数据private Entry[] table;// 数组的默认容量大小private static final int INITIAL_CAPACITY = 16;// 扩容的阈值 , 默认是数组大小的三分之二private int threshold;private void setThreshold(int len) {threshold = len * 2 / 3;}}4.2 set方法源码// 给ThreadLocal设值public void set(T value) {// 获取当前线程对象Thread t = Thread.currentThread();// 获取此线程对象中的ThreadLocalMap对象ThreadLocalMap map = getMap(t);// 如果ThreadLocal已经设过值 , 直接设值 , 否则初始化if (map != null)// 设值的key就是当前ThreadLocal对象实例 , value是ThreadLocal泛型对象值map.set(this, value);else// 初始化ThreadLocalMapcreateMap(t, value);}再看一下实际的set方法源码:// key就是当前ThreadLocal对象实例 , value是ThreadLocal泛型对象值private void set(ThreadLocal<?> key, Object value) {// 获取ThreadLocalMap中的Entry数组Entry[] tab = table;int len = tab.length;// 计算key在数组中的下标 , 也就是ThreadLocal的hashCode和数组大小-1取余int i = key.threadLocalHashCode & (len - 1);// 查找流程:从下标i开始 , 判断下标位置是否有值 , // 如果有值判断是否等于当前ThreadLocal对象实例 , 等于就覆盖 , 否则继续向后遍历数组 , 直到找到空位置for (Entry e = tab[i];e != null;// nextIndex 就是让在不超过数组长度的基础上 , 把数组的索引位置 + 1e = tab[i = nextIndex(i, len)]) {ThreadLocal<?> k = e.get();// 如果等于当前ThreadLocal对象实例 , 直接覆盖if (k == key) {e.value = https://www.huyubaike.com/biancheng/value;return;}// 当前key是null , 说明ThreadLocal对象实例已经被GC回收了 , 直接覆盖if (k == null) {replaceStaleEntry(key, value, i);return;}}// 找到空位置 , 创建Entry对象tab[i] = new Entry(key, value);int sz = ++size;// 当数组大小大于等于扩容阈值(数组大小的三分之二)时 , 进行扩容if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash();}set方法具体流程如下:
文章插图
从源码和流程图中得知 , ThreadLocal是通过线性探测法解决哈希冲突的 , 线性探测法具体赋值流程如下:
- 通过key的hashcode找到数组下标
- 如果数组下标位置是空或者等于当前ThreadLocal对象 , 直接覆盖值结束
- 如果不是空 , 就继续向下遍历 , 遍历到数组结尾后 , 再从头开始遍历 , 直到找到数组为空的位置 , 在此位置赋值结束
4.3 get方法源码
// 从ThreadLocal从取值public T get() {// 获取当前线程对象Thread t = Thread.currentThread();// 获取此线程对象中的ThreadLocalMap对象ThreadLocalMap map = getMap(t);if (map != null) {// 通过ThreadLocal实例对象作为key , 在Entry数组中查找数据ThreadLocalMap.Entry e = map.getEntry(this);// 如果不为空 , 表示找到了 , 直接返回if (e != null) {T result = (T)e.value;return result;}}// 如果ThreadLocalMap是null , 就执行初始化ThreadLocalMap操作return setInitialValue();}
经验总结扩展阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 全方位剖析宝宝湿疹
- 深入剖析Sgementation fault原理
- Java程序员必会Synchronized底层原理剖析
- 硬核字幕组是什么意思?
- 硬核是什么梗?
- 硬核颜值是什么意思?
- 硬核父母是什么意思?
- 硬核奶奶是什么意思?
- 硬核祖母是什么意思?
- 硬核女装是什么意思?
