ThreadLocal ThreadLocalMap浅析

先发一个最常见的图

在这里插入图片描述

一:关键字 ThreadLocal ThreadLocalMap Thread

1 概念 ThreadLocal
在这里插入图片描述
理解:ThreadLocal类用来设置线程私有变量 本身不储存值 主要提供自身引用 和 操作ThreadLocalMap 属性值得方法,使用ThreadLocal会通过ThreadLocal的引用定位到到堆中Thread的类ThreadLocalMap里散列表里的值 从而达到线程私有

目的:解决多线程使用共享对象的问题 空间换时间

2 存储形式:ThreadLocalMap(ThreadLocal 的静态内部类 由ThreadLocal类来维护和创建)中

  • a:和普通Hashmap类似存储在一个数组内,但与hashmap使用的拉链法解决散列冲突的是 ThreadLocalMap使用开放地址法
    //开放地址法缺点 :
    -空间利用率低 开发地址发会在散列冲突时寻找下一个可存入的槽点 为了避免冲突 负载因子会设置的相对较小
    还使用的原因是 ThreadLocalMap的散列值均匀 且经常增删 纯数组较方便 节点数量少 时也能节省掉指针域带来的空间开销

  • b : 数组 初始容量16,负载因子2/3

  • c : node节点 的key封装了WeakReference 用于回收

  • d : 数组位置计算

ThreadLocalMap属性

        static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
        //初始容量16
        private static final int INITIAL_CAPACITY = 16;
        //散列表
        private Entry[] table;
        //entry 有效数量 
        private int size = 0;
        //负载因子
        private int threshold; 

ThreadLocalMap设置ThreadLocal 变量


    private void set(ThreadLocal<?> key, Object value) {
            Entry[] tab = table;
            int len = tab.length;
            
            //与运算  & (len-1) 这就是为什么 要求数组len 要求2的n次幂 
            //因为len减一后最后一个bit是1 与运算计算出来的数值下标 能保证全覆盖 
            //否者数组有效位会减半 
            //如果是hashmap 计算完下标后 会增加链表 或红黑树的查找计算量 
            int i = key.threadLocalHashCode & (len-1);
            
            // 从下标位置开始向后循环搜索  不会死循环  有扩容因子 必定有空余槽点
            for (Entry e = tab[i];   e != null;  e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
                //一种情况 是当前引用 返回值
                if (k == key) {
                    e.value = value;
                    return;
                }
                //槽点被GC掉 重设状态 
                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
			//槽点为空 设置value
            tab[i] = new Entry(key, value);
            //设置ThreadLocal数量
            int sz = ++size;
			
			//没有可清理的槽点 并且数量大于负载因子 rehash
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

3 储存位置:储存在Thread中的两个ThreadLocalMap变量
在这里插入图片描述

4:储存时机

  • threadLocals 在ThreadLocal对象方法get中去创建 也由ThreadLocal来维护
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            **createMap**(t, value);
    }

    void createMap(Thread t, T firstValue) {
        t.threadLocals = **new ThreadLocalMap**(this, firstValue);
    }
  • inheritableThreadLocals 和ThreadLocal类似 InheritableThreadLocal重写了createMap方法
void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }

inheritableThreadLocals 作用是将ThreadLocalMap传递给子线程
在这里插入图片描述
init方法中 条件满足后直接为子线程创建ThreadLocalMap
在这里插入图片描述
重要
a: 仅在初始化子线程的时候会传递 中途改变副线程的inheritableThreadLocals 变量 不会将影响结果传递到子线程 。
b:使用线程池要注意 线程不回收 尽量避免使用父线程的inheritableThreadLocals 导致错误

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值