ThreadLocal类

ThreadLocal类是啥

使用ThreadLocal类,目的是为了得到线程隔离的变量
那么,ThreadLocal类到底是啥?
其实,它就是个普通的类
那它又是如何实现我们希望的功能:得到线程隔离的变量呢?
其实很简单,每个Thread里都有一个线程独有的map,它的key就是ThreadLocal类的实例
我们通过ThreadLocal去获取线程隔离的变量,其实就是去这个map里把ThreadLocal的实例作为key去找到对应的value罢了

具体代码

首先,让我们看看ThreadLocal是怎么用的

ThreadLocal<String> tl = new ThreadLocal<>();
//设置变量
tl.set("hello");
//获取变量
tl.get();

用法很简单,但内部是如何实现的呢?往下看

Thread类

//每个thread里都有一个ThreadLocalMap,里面存着当前线程独有的变量
ThreadLocal.ThreadLocalMap threadLocals = null;

可以看出,每个thread都有个ThreadLocalMap,这里面就是该线程独有的变量集合

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);
    }
    
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

ThreadLocal.set方法,把当前线程的ThreadLocalMap拿到了,再调用ThreadLocalMapset方法设置变量,非常简单。
那么下一步就要看看ThreadLocalMap是怎么set的了

ThreadLocalMap

public class ThreadLocal<T> {
    static class ThreadLocalMap {
   		private Entry[] table;
        static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
        //其余省略
 	}
 	//其余省略
 }

可以看出,这个结构还是比较复杂的

  • ThreadLocalMapThreadLocal的内部类
  • Entry又是ThreadLocalMap的内部类
  • Entry里维护的value就是我们set的变量

ThreadLocalMap的本质,就是维护了一个Entry[],ThreadLocalMap一定是通过某种方式,把key(也就是ThreadLocal实例)对应到Entry数组的某个index

 private void set(ThreadLocal<?> key, Object value) {

     Entry[] tab = table;
     int len = tab.length;
     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;
         }

         if (k == null) {
             replaceStaleEntry(key, value, i);
             return;
         }
     }

     tab[i] = new Entry(key, value);
     int sz = ++size;
     if (!cleanSomeSlots(i, sz) && sz >= threshold)
         rehash();
 }

从上面代码可以看出,它是通过key.threadLocalHashCode & (len-1)来取到index的,然后就是设置或更新操作

梳理一下整个步骤:

  1. 调用某ThreadLocal对象的set方法
  2. ThreadLocal对象通过Thread.currentThread取到当前线程t
  3. 取到当前线程tThreadLocalMap
  4. ThreadLocal对象作为keyThreadLocalMap通过key.threadLocalHashCode & (len-1)计算出value应该放在Entry数组的哪个index
  5. 更新或插入新的Entry对象到index位置,Entry对象包含了要setvalue
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值