Java ThreadLocal源码解析: Thread和ThreadLocal

之前对TreadLocal有所理解,对原理也有所了解,但一直不深入,重新整理,希望借以加深理解和印象。

在Jdk1.8中,ThreadLocal相关代码主要分为三部分:

  • Thread,其中Thread中保存对ThreadLocal.ThreadLocalMap的引用,作为Thread类的default属性;
  • ThreadLocal,类似于线程中的T和readLocal.ThreadLocalMap的管理类,提供获取、设置、删除等管理方法;
  • ThreadLocal.ThreadLocalMap.ThreadLocal,是ThreadLocal的静态内部内,底层数组结构的维护类,包含扩容、获取等功能,是ThreadLocal的底层核心实现。

1. Thread类

/* 本现场的ThreadLocal. */
ThreadLocal.ThreadLocalMap threadLocals = null;

/*
 *  继承自父类来的ThreadLocal.
 */
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

通过Thread的构造函数可知默认情况下,inheritableThreadLocals会通过父类的threadLocal初始化,除非特别指明不继承父类的threadLocal。

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
                      …… ……
                    // 如果指明要继承,并且父线程的threadLocal不为空
			        if (inheritThreadLocals && parent.inheritableThreadLocals != null)  
			            // 通过ThreadLocal创建inheritableThreadLocals 
			            this.inheritableThreadLocals =
			                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
			        /* Stash the specified stack size in case the VM cares */
			        this.stackSize = stackSize;			        
					  …… ……
}

小结:每个线程中都有两个属性,即两个ThreadLocalMap,其中一个为线程自己的,一个是初始化线程时,从父线程中的拿来创建的,默认如果父线程有threadLocal,子线程会继承父线程的threadLocal.

2. ThreadLocal类

前文中所说的,ThreadLocal类类似于ThreadLocalMap管理端。ThreadLocal中主要属性和方法如下图:
在这里插入图片描述
以下是ThreadLocal中核心方法分析:

    // 使用线性探测法进行map的扩容
    private final int threadLocalHashCode = nextHashCode();

    /**
     * 静态全局的存储下一个hash码
     */
    private static AtomicInteger nextHashCode =
        new AtomicInteger();

    /**
     * hashCode增量
     */
    private static final int HASH_INCREMENT = 0x61c88647;
    
    // 下一个hashCode增加增量
    private static int nextHashCode() {
    	return nextHashCode.getAndAdd(HASH_INCREMENT);
   }
   
   /* 重要逻辑,当线程1调用ThreadLocal的get()方法时,首先拿到线程1的threadLocals属性,
     * 如果不为空,  通过以当前ThreadLocal为key值获取ThreadLocal中存放的值。这里有点绕,
     * 实际相当于,在执行ThreadLocal<String> threadLocal = new ThreadLocal<String>();后,通
     * 过get()方法,将拿到线程1中threadLocals通过get()方法以threadLocal为key值的设置的值。
     * /
   public T get() {
        Thread t = Thread.currentThread();  //获取当前线程
        ThreadLocalMap map = getMap(t);  //获取当前线程的ThreadLocalMap, 即那个属性
        if (map != null) {     // 如果当前线程存在ThreadLocal
            ThreadLocalMap.Entry e = map.getEntry(this);   // ThreadLocalMap中以ThreadLocal为key,获取ThreadLocalMap中存放的值
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;  // 转化为正确格式,泛型
                return result;
            }
        }
        return setInitialValue();
  }

   /*
    *  setInitialValue和set(T value)内部逻辑类似,只是一个传了初始值,一个没有,如果没传初始值,则为null
    */
   private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();  // 获取当前线程
        ThreadLocalMap map = getMap(t);   // 拿到当前线程的threadLocals,
        if (map != null)
            map.set(this, value);   // 在threadLocalMap中设置key为当前ThreadLocal, value为value的值
        else
            createMap(t, value);  // 创建一个ThreadLocalMap,并把引用赋值给当前线程的threadLocals
        return value;
    }

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

  void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);  //为当前线程创建一个threadMap
    }
    static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {  //这是个静态方法,在Thread中调用,即如果要继承父类的threadLocal,将通过这个房间创建
        return new ThreadLocalMap(parentMap);
    }

总结:重要的是ThreadLocal中的get和set方法,get方法将最终拿到当前线程的threadLocals,这是一个map,在set的时候以ThreadLocal为key值,实际上是以ThreadLocal的threadLocalHashCode为key值。

猜你喜欢

转载自blog.csdn.net/qq_36101933/article/details/82905655