ThreadLocal 源码解析

疑问:

1、为什么不同线程使用同一个ThreadLocal获取Value,获取到的Value都是每个线程特有的呢?
答:因为ThreadLocal依赖于自定义的ThreadLocalMap进行存储,而这个ThreadLocalMap就存在的Thread中,所以每个线程都有自己的ThreadLocalMap。ThreadLocal只是一个入口,最终找到的都是在线程自己的ThreadLocalMap中查找对应value。
2、为什么ThreadLocal的哈希值增量是0x61c88647?
答:

变量:

private final int threadLocalHashCode = nextHashCode();
意义:通过nextHashCode()方法计算出来,自定义的哈希值,用来确定在ThreadLocalMap中的位置。

private static AtomicInteger nextHashCode = new AtomicInteger();
意义:储存下一个ThreadLocal的哈希值,因为使用了原子类AtomicInteger,所以不存在线程安全问题。

private static final int HASH_INCREMENT = 0x61c88647;
意义:这是一个很神奇的值,用来计算ThreadLocal的哈希值,尽可能的是Entry在Map中分布均匀。

方法:

public ThreadLocal()
意义:这是一个正经的构造方法。

private static int nextHashCode()
意义:返回并且计算下一个ThreadLocal的哈希值。

protected T initialValue()
意义:返回这个ThreadLocal的初始值。

public T get()
意义:获取ThreadLocal在当前线程的ThreadLocalMap中对应的value。

private T setInitialValue()
意义:如果ThreadLocalMap还没初始化,就会先初始化ThreadLocalMap,然后会把ThreadLocal与initialValue()存进去,最后返回initialValue()的值。

public void set(T value)
意义:把ThreadLocal与参数中的value放进ThreadLocalMap中去。如果ThreadLocalMap为空,则会先创建ThreadLocalMap。

public void remove()
意义:从ThreadLocalMap中移除这个ThreadLocal对应的Entry。

ThreadLocalMap getMap(Thread t)
意义:获取线程中的ThreadLocalMap

void createMap(Thread t, T firstValue)
意义:添加ThreadLocalMap到参数中的Thread中,然后把参数中的firstValue放入ThreadLocalMap中。

static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap)
意义:根据父类的ThreadLocalMap,创建子类的ThreadLocalMap。其中子类的ThreadLocalMap拥有父类ThreadLocalMap中所有值。

T childValue(T parentValue)
意义:???

public static ThreadLocal withInitial(Supplier<? extends S> supplier)
意义:???

下面是枯燥的源码解析:

/**
 * 这个类是提供线程本地变量,这些变量不同于普通变量,每一个线程通过Get和Set方法访问自己的一个
 * 独立的初始化变量副本,ThreadLocal实例通常是类中希望将状态与线程关联的私有字段。
 * (例如:用户ID或事物ID)
 * 
 * 例如,下面的类为每个线程分配一个唯一的标识符。
 * 一个线程的id在它第一次被调用ThreadId.get()方法的时候分配,并且在后面的调用中保持不变。
 * <pre>
 * import java.util.concurrent.atomic.AtomicInteger;
 *
 * public class ThreadId {
 *     // Atomic integer containing the next thread ID to be assigned
 *     private static final AtomicInteger nextId = new AtomicInteger(0);
 *
 *     // Thread local variable containing each thread's ID
 *     private static final ThreadLocal&lt;Integer&gt; threadId =
 *         new ThreadLocal&lt;Integer&gt;() {
 *             &#64;Override protected Integer initialValue() {
 *                 return nextId.getAndIncrement();
 *         }
 *     };
 *
 *     // Returns the current thread's unique ID, assigning it if necessary
 *     public static int get() {
 *         return threadId.get();
 *     }
 * }
 * </pre>
 * 只要线程是存活的,并且ThreadLocal是可到达的,那么每个线程持有着一个ThreadLocal变量的隐式引用。
 * 在一个线程结束之后,它的所有ThreadLocal变量副本会被GC(除非存在着对这个副本的引用)
 *
 * @author  Josh Bloch and Doug Lea
 * @since   1.2
*/
public class ThreadLocal<T> {

	/**
	 * ThreadLocal依赖于附加在每个线程上的线性探头HashMaps。
	 * (Thread.threadLocals和Thread.inheritableThreadLocals)
	 * ThreadLocal对象担任Key的角色,通过ThreadLocal哈希值查找value。
	 * 这是一个自定义的哈希值(只在ThreadLocalMaps中可用),
	 * 为了解决通常情况下同一个线程不断地构造ThreadLocal而发生的冲突,
	 * 而在不常见的情况下,也有良好的表现。
	 */
    private final int threadLocalHashCode = nextHashCode();

    /**
     * 将会提供下一个哈希值。以零开始,原子性的更新。
     */
    private static AtomicInteger nextHashCode =
        new AtomicInteger();

    /**
     * 不断生成的哈希值之间的差异-为了倍增的table,
	 * 将隐式连贯的ThreadLocalId转到将近最佳的扩展乘法哈希值。
     */
    private static final int HASH_INCREMENT = 0x61c88647;

    /**
     * 返回下一个哈希值
     */
    private static int nextHashCode() {
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    }

	/**
	 * 为这个ThreadLocal变量返回一个当前线程的初始值。
	 * 当线程第一次用get方法访问变量的时候,这个方法就会被调用。
	 * 除非线程之前调用过set方法,在这种情况下initialValue方法将不会被线程调用。
	 * 通常地,每个线程最多调用一次这个方法,但是如果在调用get方法之后调用remove方法,
	 * 那么会再次调用initialValue方法。
	 * 
	 * 建议:这里的实现简单地返回了空。
	 *       如果程序员希望ThreadLocal变量有一个不是null的初始值,
	 *       ThreadLocal一定要被继承,并且这个方法要被覆盖。
	 *       典型地,一个匿名内部类将会被使用。
     *
     * @return 这个ThreadLocal的初始值
     */
    protected T initialValue() {
        return null;
    }

    /**
     * 创建一个ThreadLocal变量。
	 * 这个变量的初始值却决于在Supplier中调用的get方法。
     *
     * @param <S> ThreadLocal值得类型
     * @param supplier Supplier被用来决定初始值
     * @return 一个新的ThreadLocal变量
     * @throws NullPointerException 如果指定的supplier是空
     * @since 1.8
     */
    public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
        return new SuppliedThreadLocal<>(supplier);
    }

    /**
     * 创建一个ThreadLocal变量
     * @see #withInitial(java.util.function.Supplier)
     */
    public ThreadLocal() {
    }

    /**
	 * 返回这个ThreadLocal变量在当前线程副本的值。
	 * 如果这个变量在当前线程中没有值,它首先会通过调用initialValue方法去初始值。
     *
     * @return 当前线程这个ThreadLocal的值
     */
    public T get() {
		//首先获得当前线程
        Thread t = Thread.currentThread();
		//获得当前线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
		//如果当前线程已经初始化ThreadLocalMap
        if (map != null) {
			//从ThreadLocalMap中拿出这个ThreadLocal对应的Entry
            ThreadLocalMap.Entry e = map.getEntry(this);
			//如果找到对应的Entry
            if (e != null) {
				//返回Entry中的value
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
		//如果当前现成的ThreadLocalMap为空
		//或者找不到ThreadLocal对应的Entry
		//调用这个方法初始化
        return setInitialValue();
    }

    /**
	 * 作为set()的变体,去构建初始值。
	 * 万一用户已经覆盖了set()方法,用来替代set()方法。
     *
     * @return 初始化的值
     */
    private T setInitialValue() {
		//获取初始值
        T value = initialValue();
		//获得当前线程的ThreadLocalMap
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
		//如果ThreadLocalMap存在
        if (map != null)
            map.set(this, value);//把ThreadLocal与value存入ThreadLocalMap中
        else
            createMap(t, value);//否则创建ThreadLocalMap,并且存入ThreadLocal与Value
		//返回初始化的value
        return value;
    }

    /**
	 * 设置这个ThreadLocal变量在当前线程的副本为一个确认的值。
	 * 大部分子类不需要去覆盖这个方法,仅依赖于initialValue()方法
	 * 去设置ThreadLocal的值。
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {
		//获得当前线程的ThreadLocalMap
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)//如果ThreadLocalMap存在,把ThreadLocal与value存入其中。
            map.set(this, value);
        else//否则创建ThreadLocalMap,并且存入ThreadLocal与Value
            createMap(t, value);
    }

    /**
     * 移除这个ThreadLocal变量在当前线程的值。
	 * 如果这个ThreadLocal变量随后被当前线程读取,
	 * 它的值将会通过调用initialValue()方法被重新初始化,
	 * 除非与此同时,它的值被当前线程set()了。
	 * 这可能导致当前线程多次调用initialValue()方法。
     *
     * @since 1.5
     */
     public void remove() {
		 //获得当前线程的ThreadLocalMap
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);//从当前线程的ThreadLocalMap中移除本ThreadLocal
     }

    /**
     * 获取线程中的ThreadLocalMap。
     * 在InheritableThreadLocal中,已经被覆盖了。
     *
     * @param  t 当前线程
     * @return 返回当前线程的ThreadLocalMap
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    /**
     * 创建一个当前线程的ThreadLocalMap,
	 * 并且把当前ThreadLocal与参数中的value作为第一个Entry放入。
     *
     * @param t 当前线程
     * @param firstValue ThreadLocal中初始Entry的value
     */
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

    /**
     * 这个工厂方法可以创建一个继承ThreadLocal的ThreadLocalMap。
     * 这个方法被设计来仅在Thread构造器中使用。
     *
     * @param  parentMap 父线程的ThreadLocalMap
     * @return 包含父ThreadLocalMap所有Entry的子ThreadLocalMap
     */
    static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
        return new ThreadLocalMap(parentMap);
    }

	/**
	 * childValue()方法显然是在子类InheritableThreadLocal中定义的,
	 * 但是在这里被内部定义是因为在InheritableThreadLocal中,
	 * 不需要得到ThreadLocalMap子类的情况下,提供createInheritedMap()静态工厂方法。
	 * 这个技术比把实例测试嵌入在方法中更好。
	 */
    T childValue(T parentValue) {
        throw new UnsupportedOperationException();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值