疑问:
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<Integer> threadId =
* new ThreadLocal<Integer>() {
* @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();
}