FastThreadLocal是啥?
它本质上还是一个ThreadLocal。但从它的名称,可以知道它比普通的ThrealLocal要快。
一.构造函数
实例FastThreadLocal时,获取一个在InternalThreadLocalMap中的索引标识。
InternalThreadLocalMap就是一个挂羊头卖狗肉的,内部使用一个数组存数据。
// 用于标志在InternalThreadLocalMap的位置
private final int index;
public FastThreadLocal() {
index = InternalThreadLocalMap.nextVariableIndex();
}
二.set
先来看看set方法
public final void set(V value) {
// InternalThreadLocalMap.UNSET 是初始化时默认添加的对象
if (value != InternalThreadLocalMap.UNSET) {
// 这个是核心优化点
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
setKnownNotUnset(threadLocalMap, value);
} else {
remove();
}
}
1. InternalThreadLocalMap.get()
InternalThreadLocalMap.get()是个关键点,这里进行了快慢区分。
public static InternalThreadLocalMap get() {
Thread thread = Thread.currentThread();
// 这里表明了FastThreadLocal要和FastThreadLocalThread搭配使用才高效
if (thread instanceof FastThreadLocalThread) {
return fastGet((FastThreadLocalThread) thread);
} else {
// 普通线程走普通方法
return slowGet();
}
}
private static InternalThreadLocalMap fastGet(FastThreadLocalThread thread) {
InternalThreadLocalMap threadLocalMap = thread.threadLocalMap();
if (threadLocalMap == null) {
thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());
}
return threadLocalMap;
}
private static InternalThreadLocalMap slowGet() {
ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = UnpaddedInternalThreadLocalMap.slowThreadLocalMap;
// 这里的操作相对而言会比较耗时
InternalThreadLocalMap ret = slowThreadLocalMap.get();
if (ret == null) {
ret = new InternalThreadLocalMap();
slowThreadLocalMap.set(ret);
}
return ret;
}
FastThreadLocalThread为什么快呢?
因为普通的ThreadLocal获取对象,首先要进行hash计算,然后处理hash冲突问题。而FastThreadLocalThread则不需要这个,对象直接作为其属性存储。
继续看实例化InternalThreadLocalMap。
private InternalThreadLocalMap() {
super(newIndexedVariableTable());
}
private static Object[] newIndexedVariableTable() {
Object[] array = new Object[32];
// 默认填充了UNSET对象,与set时的判断对应
Arrays.fill(array, UNSET);
return array;
}
2.setKnownNotUnset
回到set方法,继续看setKnownNotUnset的操作。
private boolean setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
// 将数据存入threadLocalMap中
if (threadLocalMap.setIndexedVariable(index, value)) {
// 走到这里表明是插入了新的线程数据
addToVariablesToRemove(threadLocalMap, this);
return true;
}
return false;
}
public boolean setIndexedVariable(int index, Object value) {
Object[] lookup = indexedVariables;
// 这里判断是否需要扩容
if (index < lookup.length) {
Object oldValue = lookup[index];
lookup[index] = value;
return oldValue == UNSET;
} else {
// 进行扩容操作
expandIndexedVariableTableAndSet(index, value);
return true;
}
}
private void expandIndexedVariableTableAndSet(int index, Object value) {
Object[] oldArray = indexedVariables;
final int oldCapacity = oldArray.length;
int newCapacity = index;
// 扩容两倍,与HashMap里面的扩容类似
newCapacity |= newCapacity >>> 1;
newCapacity |= newCapacity >>> 2;
newCapacity |= newCapacity >>> 4;
newCapacity |= newCapacity >>> 8;
newCapacity |= newCapacity >>> 16;
newCapacity ++;
Object[] newArray = Arrays.copyOf(oldArray, newCapacity);
// 扩容的数据都填充UNSET对象
Arrays.fill(newArray, oldCapacity, newArray.length, UNSET);
newArray[index] = value;
indexedVariables = newArray;
}
3.addToVariablesToRemove
通过源码可知,addToVariablesToRemove这个操作是存放新加入的FastThreadLocal对象。
// 这里的static,final表明了variablesToRemoveIndex初始化时设置好,故而一直为0
private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();
private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
// 这里获取threadLocalMap索引为0的数据
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
Set<FastThreadLocal<?>> variablesToRemove;
// 首次设置,则初始化
if (v == InternalThreadLocalMap.UNSET || v == null) {
variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<FastThreadLocal<?>, Boolean>());
threadLocalMap.setIndexedVariable(variablesToRemoveIndex, variablesToRemove);
} else {
variablesToRemove = (Set<FastThreadLocal<?>>) v;
}
// 将新加入的FastThreadLocal存入
variablesToRemove.add(variable);
}
三.remove
remove比较简单,主要做了两个操作:
- 重置threadLocalMap中对应的索引数据
- 移除threadLocalMap索引为0的数据中包含的当前FastThreadLocal
public final void remove() {
// InternalThreadLocalMap.getIfSet()获取InternalThreadLocalMap对象与前文类似
remove(InternalThreadLocalMap.getIfSet());
}
public final void remove(InternalThreadLocalMap threadLocalMap) {
...
// 设置index对应数据为默认值
Object v = threadLocalMap.removeIndexedVariable(index);
// 移除当前的FastThreadLocal
removeFromVariablesToRemove(threadLocalMap, this);
...
}
public Object removeIndexedVariable(int index) {
Object[] lookup = indexedVariables;
if (index < lookup.length) {
Object v = lookup[index];
// 重置index对应值为默认值
lookup[index] = UNSET;
return v;
} else {
return UNSET;
}
}
private static void removeFromVariablesToRemove(
InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
// 获取索引0位置的数据
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
if (v == InternalThreadLocalMap.UNSET || v == null) {
return;
}
// 执行set的remove操作
Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
variablesToRemove.remove(variable);
}