首页 / JAVA  

ThreadLocal ,ThreadLocalMap 和Thread 的关系

Thread 中持有一个ThreadLocalMap ,这里你可以简单理解为就是持有一个数组,这个数组是Entry 类型的。
Entry 的key 是ThreadLocal 类型的,value 是Object 类型。也就是一个ThreadLocalMap 可以持有多个ThreadLocal。


为什么ThreadLocalMap 设计为ThreadLocal 内部类


ThreadLocalMap 是一个线程本地的值,它所有的方法都是private 的,也就意味着除了ThreadLocal 这个类,其他类是不能操作ThreadLocalMap 中的任何方法的,这样就可以对其他类是透明的。同时这个类的权限是包级别的,也就意味着只有同一个包下面的类才能引用ThreadLocalMap 这个类,这也是Thread 为什么可以引用ThreadLocalMap 的原因,因为他们在同一个包下面。
虽然Thread 可以引用ThreadLocalMap,但是不能调用任何ThreadLocalMap 中的方法。这也就是我们平时都是通过ThreadLocal 来获取值和设置值,看下以下代码

ThreadLocal<String> local = new ThreadLocal<>();
local.set("hello word");
System.out.println(local.get());


ThreadLocal与ThreadLdocalMap的关系

但我们调用ThreadLocal 的get 方法的时候,其实我们最后是通过调用ThreadLdocalMap 来获取值的

public T get() {
    //这里通过获取当前的线程
    Thread t = Thread.currentThread();
    //通过线程来获取ThreadLocalMap ,还记得我们上面说的Thread 里面有一个ThreadLocalMap 属性吗?就是这里用上了
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

我们一值使用的都是ThreadLocal,其实ThreadLdocalMap 对使用者来说是透明的


ThreadLdocalMap 什么时候开始和Thread 进行绑定的呢

在第一次调用ThreadLocal set() 方法的时候开始绑定的,来我们看下set 方法的源码

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
    //第一次的时候进来这里,因为ThreadLocalMap 还没和Thread 绑定
        createMap(t, value);
}
//这个时候开始创建一个新的ThreadLocalMap 赋值给Thread 进行绑定
void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}


2019-10-23