承接上文,这篇主要就分析FastThreadLocal
顺带分析下相关内容
what
既然又了ThreadLocal
为什么Netty又创建了一个FastThreadLocal
呢,首先,先看下FastThreadLocal
的注释,类注释上面说明了。简述一下
- 通过
FastThreadLocalThread
访问会更快 - 取代了Hash映射,使用常量
处理频繁访问的场景
A special variant of ThreadLocal that yields higher access performance when accessed from a FastThreadLocalThread. ThreadLocal的一种特殊变体,当从FastThreadLocalThread进行访问时,会产生更高的访问性能。 Internally, a FastThreadLocal uses a constant index in an array, instead of using hash code and hash table, to look for a variable. Although seemingly very subtle, it yields slight performance advantage over using a hash table, and it is useful when accessed frequently. 在内部,FastThreadLocal使用数组中的常量索引,而不是使用哈希代码和哈希表来查找变量。虽然看起来很微妙,但它比使用哈希表产生了轻微的性能优势,并且在频繁访问时非常有用。 To take advantage of this thread-local variable, your thread must be a FastThreadLocalThread or its subtype.By default, all threads created by DefaultThreadFactory are FastThreadLocalThread due to this reason. 要利用此线程局部变量,你的线程必须是FastThreadLocalThread或其子类型。由于这个原因,默认情况下,DefaultThreadFactory创建的所有线程都是FastThreadLocalThread。 Note that the fast path is only possible on threads that extend FastThreadLocalThread, because it requires a special field to store the necessary state. An access by any other kind of thread falls back to a regular link ThreadLocal. 请注意,快速路径仅适用于扩展FastThreadLocalThread的线程,因为它需要一个特殊字段来存储必要的状态。任何其他类型的线程的访问都会回退到常规链接ThreadLocal。
Detail
简述
上一篇看过了,这里就很容易了,也是将存储对象放入到线程中,这里对象就简单粗暴了,没有通过Entry
了,而是直接通过Object[]
数组,那么是怎么定位的呢,它是通过private static final AtomicInteger nextIndex = new AtomicInteger();
来实现的,每次FastThreadLocal
创建都会获得唯一的值,自增,避免了哈希碰撞。
初始化会全部设置成一个Object
这样就可以知道FastThreadLocal
第一次塞值的地方了,第一次塞值会塞入到variablesToRemoveIndex
这个位置,这个位置比较特别,放的全是FastThreadLocal
,当线程执行完毕的时候,会比较方便的清除引用。
先记住一个大概,下面会有详细的分析,这里呢先记住个大概,下面会一一分析的
set
public final void set(V value) {
if (value != InternalThreadLocalMap.UNSET) {
//1.1
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
//1.2
setKnownNotUnset(threadLocalMap, value);
} else {
remove();
}
}
//1.1 InternalThreadLocalMap
public static InternalThreadLocalMap get() {
Thread thread = Thread.currentThread();
if (thread instanceof FastThreadLocalThread) {
//2.1
return fastGet((FastThreadLocalThread) thread);
} else {
return slowGet();
}
}
//2.1
private static InternalThreadLocalMap fastGet(FastThreadLocalThread thread) {
//同样是存储在FastThreadLocalThread中
InternalThreadLocalMap threadLocalMap = thread.threadLocalMap();
//如果没有回创建一个
if (threadLocalMap == null) {
//3.1
thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());
}
return threadLocalMap;
}
//3.1
private InternalThreadLocalMap() {
indexedVariables = newIndexedVariableTable();
}
private static Object[] newIndexedVariableTable() {
//INDEXED_VARIABLE_TABLE_INITIAL_SIZE:32
Object[] array = new Object[INDEXED_VARIABLE_TABLE_INITIAL_SIZE];
//public static final Object UNSET = new Object();
Arrays.fill(array, UNSET);
return array;
}
//1.2
private void setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
//2.2
if (threadLocalMap.setIndexedVariable(index, value)) {
//3.2
addToVariablesToRemove(threadLocalMap, this);
}
}
//2.2
public boolean setIndexedVariable(int index, Object value) {
//初始化创建的的Object[]数组,初始化的时候全是UNSET
Object[] lookup = indexedVariables;
//这个index是FastThreadLocal初始化的时候创建的时候就会赋值的,这个后面再分析
//这里说明不需要扩容
if (index < lookup.length) {
//老值
Object oldValue = lookup[index];
//设置新值
lookup[index] = value;
//比对老值是否等于UNSET
return oldValue == UNSET;
} else {
//4.1 扩容
expandIndexedVariableTableAndSet(index, value);
return true;
}
}
//3.2
private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
//private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();
//返回threadLocalMap,variablesToRemoveIndex位置的值
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
Set<FastThreadLocal<?>> variablesToRemove;
if (v == InternalThreadLocalMap.UNSET || v == null) {
variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<FastThreadLocal<?>, Boolean>());
//往threadLocalMap[variablesToRemoveIndex],设置一个Set
threadLocalMap.setIndexedVariable(variablesToRemoveIndex, variablesToRemove);
} else {
//获取该set
variablesToRemove = (Set<FastThreadLocal<?>>) v;
}
//将当前ThreadLocal添加进该set
variablesToRemove.add(variable);
}
扩容
它一大串或就是保证最高位开始后面全都为1,+1后就是2的倍数,
然后扩容,把index塞到它应该在的位置上
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;
}
初始化
下面这边是2个初始化变量,index
,每次创建的时候,会依次递增,variablesToRemoveIndex
就是所有FastThreadLocal
公用啦。
public class FastThreadLocal<V> {
private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();
private final int index;
public FastThreadLocal() {
index = InternalThreadLocalMap.nextVariableIndex();
}
}
public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {
private static final AtomicInteger nextIndex = new AtomicInteger();
public static int nextVariableIndex() {
int index = nextIndex.getAndIncrement();
if (index < 0) {
nextIndex.decrementAndGet();
throw new IllegalStateException("too many thread-local indexed variables");
}
return index;
}
}
销毁
这里主要看一下variablesToRemoveIndex
的用法了,可以参考FastThreadLocalRunnable
在执行结束后会调用removeAll
清除引用
final class FastThreadLocalRunnable implements Runnable {
private final Runnable runnable;
private FastThreadLocalRunnable(Runnable runnable) {
this.runnable = ObjectUtil.checkNotNull(runnable, "runnable");
}
@Override
public void run() {
try {
runnable.run();
} finally {
FastThreadLocal.removeAll();
}
}
}
public static void removeAll() {
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
if (threadLocalMap == null) {
return;
}
try {
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
if (v != null && v != InternalThreadLocalMap.UNSET) {
@SuppressWarnings("unchecked")
//FastThreadLocal集合
Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
FastThreadLocal<?>[] variablesToRemoveArray =
variablesToRemove.toArray(new FastThreadLocal[0]);
//遍历所有的FastThreadLocal
for (FastThreadLocal<?> tlv: variablesToRemoveArray) {
//
tlv.remove(threadLocalMap);
}
}
} finally {
InternalThreadLocalMap.remove();
}
}
public final void remove(InternalThreadLocalMap threadLocalMap) {
if (threadLocalMap == null) {
return;
}
//1.1
Object v = threadLocalMap.removeIndexedVariable(index);
//1.2
removeFromVariablesToRemove(threadLocalMap, this);
//没有删除的情况
if (v != InternalThreadLocalMap.UNSET) {
try {
//预留模板方法,自定义实现
onRemoval((V) v);
} catch (Exception e) {
PlatformDependent.throwException(e);
}
}
}
//1.1 去引用,赋值为UNSET
public Object removeIndexedVariable(int index) {
Object[] lookup = indexedVariables;
if (index < lookup.length) {
Object v = lookup[index];
lookup[index] = UNSET;
return v;
} else {
return UNSET;
}
}
//1.2
private static void removeFromVariablesToRemove(
InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
if (v == InternalThreadLocalMap.UNSET || v == null) {
return;
}
@SuppressWarnings("unchecked")
Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
//set中去掉这个FastThreadLocal
variablesToRemove.remove(variable);
}
get
这个没啥好说的,一看就懂了
public final V get() {
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
Object v = threadLocalMap.indexedVariable(index);
if (v != InternalThreadLocalMap.UNSET) {
return (V) v;
}
return 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;
}
总结
FastThreadLocal
主要核心我觉得就是通过index来取代哈希运算了,但是这样可能带来一个小问题,别频繁创建,why就不分析了,注释写的很清楚了,就是为了速度,over~~
本文由mdnice多平台发布
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。