类ThreadLoal 的主要作用是将数据放入当前线程的map中,这个map是thread的实例变量。类ThreadLoal 自己不会进行管理,不存储任何数据,它只是数据和map之间的桥梁。用于将数据放入map中。执行流程如下

ThreadLocal原理剖析_ThreadLocal

执行后,每个线程中的map都有自己的数据,key为ThreadLocaL对象,value为存储的值。每个thread中map中的值只对当前线程可见,其他线程不可以访问。当前线程销毁,map也随之销毁,map中的值如果没有被引用、没有被使用,则GC随时收回。

由于key不可以重复,所有一个ThreadLocal对象对应一个value值,结构如下

ThreadLocal原理剖析_多线程_02

我们在使用时通常 :private static ThreadLocal threadLocal = new ThreadLocal(); 用 private static 修饰

每个线程Thread都有自己私有的ThreadLocalMap对象属性

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

ThreadLocal类中的get()方法

public T get() {
        Thread t = Thread.currentThread();//获取当前的线程
        ThreadLocalMap map = getMap(t);//获取当前线程私有的ThreadLocalMap实例
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);//内部维护着entry对象
            if (e != null) {//不为空,说明已经存在实例
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;//返回value值
            }
        }
        return setInitialValue();//为空,就设置初始化值
    }
 ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;//根据当前线程,返回私有的ThreadLocalMap实例
    }

 private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

以protected修饰,方便我们重写、设置初始值

protected T initialValue() {
        return null;
    }
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);//直接将当前的value赋值到私有的ThreadLocalMap中
        else
            createMap(t, value);//第一次使用,创建map
    }

那既然thread中有ThreadLocal.ThreadLocalMap threadLocals = null; 那为什么不直接存取数据呢?

ThreadLocal.ThreadLocalMap threadLocals = null;//默认访问时包级别,外部无法直接访问

但是ThreadLocal 和 Thread 是在同一包 java.long ,所以可以作为桥梁间接访问

ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用,也即变量在线程间隔离而在方法或类间共享的场景。