功能概述
- 对ThreadLocal的封装处理,内部使用的数据结构是数组,而ThreadLocal是使用hashCode来计算处理的,多了一步计算,还得解决hash冲突,所以InternalThreadLocal的访问性能更高
- InternalThreadLocalMap:内部的线程局部变量的Map【用于存储线程的局部变量值,存储的结构是一个数组,而不是一个Map(快慢获取的元素,本质在于数组结构的不同)】
功能分析
核心类InternalThreadLocal分析
主要成员变量分析
private static final int VARIABLES_TO_REMOVE_INDEX = InternalThreadLocalMap.nextVariableIndex(); //InternalThreadLocal类型的缓存集合在InternalThreadLocalMap对应的下标
private final int index; //普通的缓存对象在InternalThreadLocalMap对应的下标(final修饰的变量为常量,表明一旦赋值后,就不能再改动,所以可以看出是一个对象一个index值(所以同一个InternalThreadLocal对象多次设值时,是会出现覆盖的)
主要成员方法分析
构造方法
public InternalThreadLocal() { //构建对象时,由InternalThreadLocalMap分配下标
index = InternalThreadLocalMap.nextVariableIndex(); //设置下一个游标值,每使用一个InternalThreadLocal,游标就会+1
}
移除所有缓存值
public static void removeAll() { //移除所有绑定在当前线程的缓存值(包含普通对象和InternalThreadLocal对象)
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
if (threadLocalMap == null) {
return;
}
try {
Object v = threadLocalMap.indexedVariable(VARIABLES_TO_REMOVE_INDEX); //拿到InternalThreadLocal类型的缓存集合对应的下标
if (v != null && v != InternalThreadLocalMap.UNSET) {
Set<InternalThreadLocal<?>> variablesToRemove = (Set<InternalThreadLocal<?>>) v;
InternalThreadLocal<?>[] variablesToRemoveArray =
variablesToRemove.toArray(new InternalThreadLocal[variablesToRemove.size()]); //将集合Set转换为Map
for (InternalThreadLocal<?> tlv : variablesToRemoveArray) { //将每个InternalThreadLocal做移除操作
tlv.remove(threadLocalMap);
}
}
} finally {
InternalThreadLocalMap.remove();
}
}
添加InternalThreadLocal变量
private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, InternalThreadLocal<?> variable) {//添加InternalThreadLocal变量到缓存集合中(即处理第一个元素)
Object v = threadLocalMap.indexedVariable(VARIABLES_TO_REMOVE_INDEX);
Set<InternalThreadLocal<?>> variablesToRemove; //表示包含了多少个InternalThreadLocal实例
if (v == InternalThreadLocalMap.UNSET || v == null) {
variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<InternalThreadLocal<?>, Boolean>()); //将Map值转换为Set
threadLocalMap.setIndexedVariable(VARIABLES_TO_REMOVE_INDEX, variablesToRemove);
} else {
variablesToRemove = (Set<InternalThreadLocal<?>>) v; //进行类型强转
}
variablesToRemove.add(variable); //InternalThreadLocalMap中的第一个元素是集合类型,如indexedVariables[0]为Collections$SetFromMap@1751
}
获取当前线程维护的值
public final V get() { //从当前线程中获取当前维护的值(若没有查找到值,会进行初始化)
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get(); //与set()获取InternalThreadLocalMap方式一致
Object v = threadLocalMap.indexedVariable(index); //获取当前对象对应index对应的值
if (v != InternalThreadLocalMap.UNSET) { //若值不为UNSET,则直接返回
return (V) v;
}
return initialize(threadLocalMap); //若不存在值,则进行初始化操作
}
初始化操作
private V initialize(InternalThreadLocalMap threadLocalMap) { //做初始化,并返回初始化后的值
V v = null;
try {
v = initialValue(); //调用子类重写的方法,若子类没有重写,则值为null
} catch (Exception e) {
throw new RuntimeException(e);
}
threadLocalMap.setIndexedVariable(index, v); //此处设置的逻辑,和set()的内部逻辑一致
addToVariablesToRemove(threadLocalMap, this);
return v;
}
设置值到当前线程
public final void set(V value) {
if (value == null || value == InternalThreadLocalMap.UNSET) {
remove(); //设置的值为空时,做移除处理(与调用remove()方法是等价的)
} else {
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
if (threadLocalMap.setIndexedVariable(index, value)) { //将值设置到InternalThreadLocalMap维护的数组中
addToVariablesToRemove(threadLocalMap, this); //将当前的InternalThreadLocal对象设置到缓存的InternalThreadLocal集合中
}
}
}
移除单个缓存值
public final void remove(InternalThreadLocalMap threadLocalMap) { //从InternalThreadLocalMap中移除指定下标index对应的值(此处语义上不太好理解,就是没有通过方法参数传递index,而是通过操作成员变量的方式)
if (threadLocalMap == null) {
return;
}
Object v = threadLocalMap.removeIndexedVariable(index); // 1)移除指定下标的普通对象的缓存值,并返回移除前的值
removeFromVariablesToRemove(threadLocalMap, this); // 2)将当前InternalThreadLocal对象从InternalThreadLocal类型的缓存集合中移除
if (v != InternalThreadLocalMap.UNSET) { //当前InternalThreadLocal有设置过值,则对应回调子类方法
try {
onRemoval((V) v); // 3)看子类的具体移除实现(回调子类的方法)
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
核心类InternalThreadLocalMap分析
主要成员变量分析
private Object[] indexedVariables; //缓存对象对应的数组(不是static变量,非共享,每个对象各自维护,是线程安全的)
private static ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = new ThreadLocal<InternalThreadLocalMap>(); //原生的ThreadLocal,每个线程维护各自的线程变量(原生的ThreadLocal使用get()获取值时,会通过计算hashCode进行查找处理)
private static final AtomicInteger NEXT_INDEX = new AtomicInteger(); //记录数组可设值的下标(下一个设置的值,对应的下标,static变量,属于公共资源,初始值为0)
public static final Object UNSET = new Object(); //当未设置值时,给出的默认值(用于填充使用)
主要成员方法分析
获取InternalThreadLocalMap
public static InternalThreadLocalMap get() { //获取InternalThreadLocalMap,返回的值若为空,会初始化对象返回
Thread thread = Thread.currentThread();
if (thread instanceof InternalThread) {
return fastGet((InternalThread) thread); //比较快的获取值
}
return slowGet(); //比较慢的获取值
}
设置线程局部变量的值
public boolean setIndexedVariable(int index, Object value) { //设置线程局部变量的值(设置成功返回true)
Object[] lookup = indexedVariables; //引用赋值,lookup数组改变,indexedVariables数组也对应改变
if (index < lookup.length) {
Object oldValue = lookup[index];
lookup[index] = value;
return oldValue == UNSET; //@csy 此处是何意?解:若老的值为UNSET,说明值已经从UNSET -> value改变了
} else {
expandIndexedVariableTableAndSet(index, value); //扩容处理
return true;
}
}
快速获取InternalThreadLocalMap
private static InternalThreadLocalMap fastGet(InternalThread thread) { //比较快的获取InternalThreadLocalMap
InternalThreadLocalMap threadLocalMap = thread.threadLocalMap(); //从InternalThread直接获取
if (threadLocalMap == null) {
thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());
}
return threadLocalMap;
}
较慢获取InternalThreadLocalMap
private static InternalThreadLocalMap slowGet() { //比较慢的获取InternalThreadLocalMap
ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = InternalThreadLocalMap.slowThreadLocalMap;
InternalThreadLocalMap ret = slowThreadLocalMap.get(); //使用ThreadLocal获取,内部是通过hashCode去获取值的
if (ret == null) {
ret = new InternalThreadLocalMap(); //初始化InternalThreadLocalMap
slowThreadLocalMap.set(ret); //将值设置set到ThreadLocal中(get时可取到set的值)
}
return ret;
}
扩容并设置线程变量的值
private void expandIndexedVariableTableAndSet(int index, Object value) { //扩容并设置线程变量的值
Object[] oldArray = indexedVariables;
final int oldCapacity = oldArray.length;
int newCapacity = index;
newCapacity |= newCapacity >>> 1; //无符号右移
newCapacity |= newCapacity >>> 2;
newCapacity |= newCapacity >>> 4;
newCapacity |= newCapacity >>> 8;
newCapacity |= newCapacity >>> 16;
newCapacity++;
Object[] newArray = Arrays.copyOf(oldArray, newCapacity); //使用数组拷贝
Arrays.fill(newArray, oldCapacity, newArray.length, UNSET);
newArray[index] = value;
indexedVariables = newArray;
}
问题点答疑
-
InternalThread.get值时,是怎么区分当前线程的?一个线程能存储多个变量吗?
- 解答:通过Thread.currentThread(); if (thread instanceof InternalThread) 来判断 一个线程可以创建多个InternalThreadLocal对象,每个InternalThreadLocal维护一个对象值,所以一个线程是存储多个变量的
-
InternalThreadLocalMap#getIfSet待了解?
- 解答:从InternalThread中或InternalThreadLocalMap维护的ThreadLocal获取到InternalThreadLocalMap值
-
InternalThreadLocalMap功能用途是怎样的?怎么使用的?
- 解答:用来存储线程局部变量的数据结构,包含的成员变量有缓存对象对应的数组以及下标
-
InternalThreadLocalMap#fastGet与slowGet有什么差异?
- 解答:fastGet()是从InternalThread获取的,获取会快些,而slowGet()是从ThreadLocal获取的,获取会慢些
-
InternalThreadLocal#VARIABLES_TO_REMOVE_INDEX变量的用途是什么?(OK)
- 解答:InternalThreadLocalMap#indexedVariables维护的数组中既有InternalThreadLocal对应的集合,也有对应的缓存对象。
-
InternalThreadLocal与InternalThread、InternalThreadLocalMap三者之间是怎么关联的?(OK)
- 解答:InternalLocalThreadMap:负责值的存储以及下标的产生InternalThreadLocal:按对象维度隔离数据,每个对象的值存储在InternalThreadLocalMap指定下标的元素中InternalThread: 按线程维度隔离数据,每个线程各自的私有变量都存在各自的InternalThradLocalMap中
归纳总结
- 在Java中,ThreadLocal是实现线程安全的一种手段,它的作用是对于同一个ThreadLocal变量,在每一个线程中都有一个副本,当修改任何一个线程的变量时,不会影响到其他线程。它通过在每一个Thread中存储一个类似于map的结构,以ThreadLocal变量为key,变量值为value。Dubbo在RPC调用的上下文中,需要借助ThreadLocal保存上下文。通过ThreadLocal,可用于传递参数InternalThreadLocal 是 ThreadLocal 的增强版,所以他们的用途都是一样的,一言蔽之就是:传递信息。