【八股】ThreadLocal原理

宏观描述

每个线程都有ThreadLocalMap,ThreadLocalMap是在ThreadLocal类里面定义的一个类似哈希表的数据结构。
ThreadLocal的作用是作为线程的ThreadLocalMap的key,获取值为value的资源变量。

1. Thread.java

我们首先打开Thread.java源码,看到里面有一个ThreadLocalMap类型的变量threadLocals
在这里插入图片描述

2. ThreadLocal.java -> getMap(thread t)

然后ThreadLocal.java里面有一个getMap函数,传入的是线程,返回的是线程里面的ThreadLocalMap
在这里插入图片描述

3. ThreadLocal.java -> set(T value)

最后看到ThreadLocal.java源码里的set函数,他的做法是找到当前线程的ThreadLocalMap,然后往里面传入key为ThreadLocal,value为资源对象的Entry
one more thing: 这个泛型T是初始化ThreadLocal时要传入的类型,T表示资源对象的类型。
在这里插入图片描述

所以ThreadLocal,ThreadLocalMap,Thread的关系是这样:
每个Thread里面都有一个类型为ThreadLocalMap的变量,这个ThreadLocalMap类型的变量其实就是个哈希表(这个哈希表的哈希函数是自己设计的,没直接用集合的HashMap)这个哈希表里面的每个Entry的key为ThreadLocal,value为资源对象。


最后我提出个问题: 每个线程里面已经有ThreadLocalMap类型的变量了,为什么还需要ThreadLocal,直接存线程的ThreadLocalMap变量里,需要的时候直接拿不就行了嘛?也就是说,ThreadLocal的作用是什么?
我的思考: 每个Thread里的ThreadLocalMap,里面可以存很多个不同key类型的Entry(kv对),比如可以存User,存Shop等等,那么怎么快速得到线程里User类型的资源呢,这时候就需要用到指定泛型的ThreadLocal作为key啦,假如我们要得到User类型资源,那么我们就可以创建一个private static final ThreadLocal<User> tl_user = new ThreadLocal<>();,也就是创建一个泛型为User类型的ThreadLocal,后面如果要在线程中取User类型的资源就直接用tl_user作为key就行啦,就能快速查到User类型资源的value。

InheritableThreadLocal原理

如果我们需要在子线程种获取到父线程的ThreadLocal数据,普通的ThreadLocal就实现不了,这时候我们就需要用到InheritableThreadLocal
每个Thread里面都有两个ThreadLocalMap。

 /* ThreadLocal values pertaining to this thread. This map is maintained
 * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;

/*
 * InheritableThreadLocal values pertaining to this thread. This map is
 * maintained by the InheritableThreadLocal class.
 */
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

Thread类里面的的每个构造方法最终都会走到下面这个构造方法里,里面把父线程的InheritableThreadLocals复制了一份给子线程的InheritableThreadLocals。

private Thread(ThreadGroup g, Runnable target, String name,
                   long stackSize, AccessControlContext acc,
                   boolean inheritThreadLocals) {
        //...省略其他代码
        
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        
        //...省略其他代码
    }

并且InheritableThreadLocal重写了getMap和createMap方法,获取到的ThreadLocalMap都是Thread里面的InheritableThreadLocals而不是ThreadLocals。

/**
 * Get the map associated with a ThreadLocal.
 *
 * @param t the current thread
 */
ThreadLocalMap getMap(Thread t) {
   return t.inheritableThreadLocals;
}

/**
 * Create the map associated with a ThreadLocal.
 *
 * @param t the current thread
 * @param firstValue value for the initial entry of the table.
 */
void createMap(Thread t, T firstValue) {
    t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}

参考文献

InheritableThreadLocal原理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值