ThreadLocal:CSDNhttps://mp.csdn.net/mp_blog/creation/editor/132995427
Netty中的FastThreadLocal是对Java中的FastThreadLocal的优化主要是为了解决ThreadLocal中线性查找 带来的性能下降同时实现快速查找和赋值
FastThreadLocal构建
这里的index代表一个编号,从1开始增长,内部是一个原子变量的计数器。其内部有一个属性
private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();这段代码保证了
variablesToRemoveIndex的值为0
提前说一下InternalThreadLocalMap代替了Threadlocal中的ThreadlocalMap
其内部维持了一个数组每个数组的值默认位UNSET,UNSET其实就是一个Object对象
由于InternalThreadLocalMap和ThreadlocalMap没有继承关系所以不能直接赋值给Thread对象因此Netty通过继承Thread类,来完成增强。这个类就是FastThreadLocalThread
可以看到其内部主要是维护了一个InternalThreadLocalMap
public class ThreadLocal {
private static final FastThreadLocal<String> fastThreadLocal = new FastThreadLocal(){
@Override
protected Object initialValue() throws Exception {
return "NAN";
}
};
public static void main(String[] args) {
FastThreadLocalThread fastThreadLocalThread = new FastThreadLocalThread(()->{
fastThreadLocal.set("nihao");
System.out.println(fastThreadLocal.get());
});
fastThreadLocalThread.start();
}
}
接下来先从set方法看起
public final void set(V value) {
if (value != InternalThreadLocalMap.UNSET) {
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
setKnownNotUnset(threadLocalMap, value);
} else {
remove();
}
}
set方法先判断value是否为UNSET,如果不是的话就调用get方法
public static InternalThreadLocalMap get() {
Thread thread = Thread.currentThread();
if (thread instanceof FastThreadLocalThread) {
return fastGet((FastThreadLocalThread) thread);
} else {
return slowGet();
}
}
get方法中如果是配合FastThreadLocalThread使用的话就会从中拿到InternalThreadLocalMap。
如果不是的话就调用slowGet方法,其原理就是使用原始的ThreadLocal,在通过ThreadlocalMap进行赋值。
但是这样效率明显降低了所以说FastThreadLocal只有配合FastThreadLocalThread才能发挥出高效率
此时已经那到了threadLocalMap,接下来就该进行赋值了
public final void set(V value) {
if (value != InternalThreadLocalMap.UNSET) {
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
setKnownNotUnset(threadLocalMap, value);
} else {
remove();
}
}
private void setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
if (threadLocalMap.setIndexedVariable(index, value)) {
addToVariablesToRemove(threadLocalMap, this);
}
}
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;
}
}
可以看到首先是根据inex获取到数组中的值并把value重新赋值给对应的index,如果是初始化值UNSET的话返回true
赋值完毕后如果是第一次赋值返回true,紧接着执行addToVariablesToRemove方法
private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
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;
}
variablesToRemove.add(variable);
}
variablesToRemoveIndex的值上边已经说过为0
这段代码告诉我们InternalThreadLocalMap维护的数组第一位为set集合,作用就是存储fastthreadlocal对象
接下来分析一下remove方法
这段代码的作用就是获得到FastThreadLocalMap,然后把对应index的值置为UNSET,并从set集合中移除FastThreadLocal。并调用onRemoval方法这个方法是留给使用者自己重写的可以做一些移除后的操作,比如连接关闭后进行资源释放
接下来看一下get方法
public final V get() {
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
Object v = threadLocalMap.indexedVariable(index);
if (v != InternalThreadLocalMap.UNSET) {
return (V) v;
}
return initialize(threadLocalMap);
}
第一步先获得InternalThreadLocalMap,然后获得自己(FastThreadLocal)对应的值,进行判断如果说未设置值的话就调用initialize(threadLocalMap)方法
private V initialize(InternalThreadLocalMap threadLocalMap) {
V v = null;
try {
v = initialValue();
} catch (Exception e) {
PlatformDependent.throwException(e);
}
threadLocalMap.setIndexedVariable(index, v);
addToVariablesToRemove(threadLocalMap, this);
return v;
}
其内部就是调用initialValue()方法进行赋值。此方法是交由使用者重写的,
例如
private static final FastThreadLocal<String> fastThreadLocal = new FastThreadLocal(){
@Override
protected Object initialValue() throws Exception {
return "NAN";
}
};
可以看到为了避免空值我返回了一个字符串