ThreadLocal源码

前言

本人出于学习ReentrantReadWriteLock源码,发现ReadLock的源码中记录当前线程持有读锁的次数,是记录在ThreadLocal中,因此学习了下ThreadLocal的源码

ThreadLocal学习路线

构造方法

    public ThreadLocal() {
    }
    乍看构造方法啥都没做,其实在ThreadLocal初始化的时候做了如下:
    private final int threadLocalHashCode = nextHashCode();
    
    threadLocalHashCode这个属性对应一个方法,在对象创建的时候回根据方法的
    返回值初始化该属性,又该属性是一个final的常量属性,即每一个ThreadLocal
    对象均有一个固定的值 
    
    private static int nextHashCode() {
        //随着ThreadLocal的创建递增
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    } 
    private static AtomicInteger nextHashCode =
        new AtomicInteger();     
    private static final int HASH_INCREMENT = 0x61c88647;    

set方法

set方法的流程大致如下:对于每一个线程对象来说,均含有 ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; 这个属性
ThreadLocalMap 属性对应一个数组,
数组中每一个元素对应着
绑定到线程上的对象,每当有新的ThreadLocal调用set方法,均会计算一次当前ThreadLocal对应存储在数组中的索引下标,计算公式如下:
int i = key.threadLocalHashCode & (len-1);
上面已经说明了每个ThreadLocal对象均有一个自己唯一的threadLocalHashCode
属性,即每一个ThreadLocal对象均会有自己在数组中的位置(位置冲突则向下顺移)

    public void set(T value) {
        获取当前线程
        Thread t = Thread.currentThread();
        获取当前线程的ThreadLocalMap属性 
        /**
        ThreadLocalMap getMap(Thread t) {
          return t.threadLocals;
        }
        */
        ThreadLocalMap map = getMap(t);
        判断ThreadLocalMap是否初始化,
           true:绑定变量到当前线程
           false:初始化当前线程的ThreadLocalMap属性,并绑定变量到线程上
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

get方法

    public T get() {
        获取当前线程
        Thread t = Thread.currentThread();
        获取当前线程的ThreadLocalMap属性
        ThreadLocalMap map = getMap(t);
        判断:ThreadLocalMap 是否初始化
           true:获取当前ThreadLocal对象对应的存储值
           false:调用默认的初始化方法,并返回初始化值
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

总结:
对于每一个线程对象均含有一个数组,该数组用于存储需要绑定到线程上的对象,ThreadLocal对象提供了对Thread中的数组访问与存储的方法,并且每一个ThreadLocal对象提供了自己的所在数组索引下标计算的因子。即每一个Thread可以绑定多个ThreadLocal对象到线程上,一般来说绑定的少一些,会有利于数组的查询,绑定多查询速度会降低,且绑定数目太多会引起数组的扩容。有关是否需要回收ThreadLocal上绑定的数据,由于ThreadLoaclMap上采用弱引用的方式jvm会自动回收,但是个人觉得利用ThreadLocal在web应用中作为参数传递的话,需要回收,需要去回收,因为web应用中的线程会重复利用,则绑定参数就会一直被获取

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值