13.InternalThreadLocalMap
UnpaddedInternalThreadLocalMap
InternalThreadLocalMap
继承自UnpaddedInternalThreadLocalMap
所以先来看一下这个类.
// 内部数据结构, 用于存储 Netty 和所有 FastThreadLocal 的线程局部变量.
class UnpaddedInternalThreadLocalMap {
// 如果在 Thread 中使用 FastThreadLocal, 则实际上使用 ThreadLocal 存放资源.
static final ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = new ThreadLocal<InternalThreadLocalMap>();
// 资源索引, 每一个 FastThreadLocal 对象都会有对应的ID, 即通过 nextIndex 自增得到.
static final AtomicInteger nextIndex = new AtomicInteger();
// 该值是在 InternalThreadLocalMap 构造方法中初始化, 数组默认大小 32, 并且数组中的所有值初始化为 InternalThreadLocalMap.UNSET.
Object[] indexedVariables;
// 下面这些变量在 InternalThreadLocalMap 中都会说道.
// 调用深度
int futureListenerStackDepth;
int localChannelReaderStackDepth;
Map<Class<?>, Boolean> handlerSharableCache;
IntegerHolder counterHashCode;
ThreadLocalRandom random;
Map<Class<?>, TypeParameterMatcher> typeParameterMatcherGetCache;
Map<Class<?>, Map<String, TypeParameterMatcher>> typeParameterMatcherFindCache;
StringBuilder stringBuilder;
// 在 charsetEncoderCache() 方法调用时如果为 null 就会创建 IdentityHashMap<Charset, CharsetEncoder> 实例.
Map<Charset, CharsetEncoder> charsetEncoderCache;
// 在 charsetDecoderCache() 方法调用时如果为 null 就会创建 IdentityHashMap<Charset, CharsetDecoder> 实例.
Map<Charset, CharsetDecoder> charsetDecoderCache;
// 调用 arrayList() 方法时会使用默认参数 8 来调用 arrayList(int) 方法,
// 如果 arrayList 属性为 null 则会创建 ArrayList<Object>(minCapacity) 实例;
// 否则就会清空 arrayList 集合, 并调用 ensureCapacity 方法.
ArrayList<Object> arrayList;
UnpaddedInternalThreadLocalMap(Object[] indexedVariables) {
this.indexedVariables = indexedVariables;
}
}
InternalThreadLocalMap
下面是一些比较重要的方法.
public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(InternalThreadLocalMap.class);
private static final int DEFAULT_ARRAY_LIST_INITIAL_CAPACITY = 8;
private static final int STRING_BUILDER_INITIAL_SIZE;
private static final int STRING_BUILDER_MAX_SIZE;
private static final int HANDLER_SHARABLE_CACHE_INITIAL_CAPACITY = 4;
private static final int INDEXED_VARIABLE_TABLE_INITIAL_SIZE = 32;
public static final Object UNSET = new Object();
private BitSet cleanerFlags;
// 指定 stringBuilder 的初始化大小和最大大小.
static {
STRING_BUILDER_INITIAL_SIZE =
SystemPropertyUtil.getInt("io.netty.threadLocalMap.stringBuilder.initialSize", 1024);
logger.debug("-Dio.netty.threadLocalMap.stringBuilder.initialSize: {}", STRING_BUILDER_INITIAL_SIZE);
STRING_BUILDER_MAX_SIZE = SystemPropertyUtil.getInt("io.netty.threadLocalMap.stringBuilder.maxSize", 1024 * 4);
logger.debug("-Dio.netty.threadLocalMap.stringBuilder.maxSize: {}", STRING_BUILDER_MAX_SIZE);
}
// 通过当前线程的类型获取线程值. 如果没有设置则返回 null.
public static InternalThreadLocalMap getIfSet() {
Thread thread = Thread.currentThread();
if (thread instanceof FastThreadLocalThread) {
// 由于 FastThreadLocalThread 中直接绑定了 InternalThreadLocalMap 实例, 所以可以直接获取.
return ((FastThreadLocalThread) thread).threadLocalMap();
}
// 这里说明该线程不是 FastThreadLocalThread 类型或子类.
// 通过 jdk 的 ThreadLocal 获取当前线程的值.
return slowThreadLocalMap.get();
}
// 如果当前线程没有设置值, 则会创建一个新的 InternalThreadLocalMap 实例后设置并返回.
public static InternalThreadLocalMap get() {
Thread thread = Thread.currentThread();
if (thread instanceof FastThreadLocalThread) {
// 如果为 null 则会调用 FastThreadLocalThread#setThreadLocalMap 方法添加新实例.
return fastGet((FastThreadLocalThread) thread);
} else {
// 如果为 null 则会调用 slowThreadLocalMap.set 方法添加新实例.
return slowGet();
}
}
// fastGet 和 slowGet 代码就不复制了.
// 删除当前线程的值, 没啥好说的就是删除 InternalThreadLocalMap 实例.
public static void remove() {
Thread thread = Thread.currentThread();
if (thread instanceof FastThreadLocalThread) {
((FastThreadLocalThread) thread).setThreadLocalMap(null);
} else {
slowThreadLocalMap.remove();
}
}
// 这里就是获取一个唯一ID.
public static int nextVariableIndex() {
// getAndIncrement 方法类似于 i++;
int index = nextIndex.getAndIncrement();
// 如果为负数说明已经 ++ 到超过 Int 类型的最大值(2147483647)
if (index < 0) {
nextIndex.decrementAndGet();
throw new IllegalStateException("too many thread-local indexed variables");
}
return index;
}
// 当前 ID 的上一个.
public static int lastVariableIndex() {
return nextIndex.get() - 1;
}
// 根据 FastThreadLocal 初始化的 index, 确定其在资源列表中的位置, 后续查询资源就可以根据索引快速确定位置.
public boolean setIndexedVariable(int index, Object value) {
Object[] lookup = indexedVariables; // 当前的Object[]对象
if (index < lookup.length) { // 检查当前的索引是否超过了Object数组的长度
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; // 当前的Object数组
final int oldCapacity = oldArray.length; // 当前的长度
int newCapacity = index; // index是这个FastThreadLocal对应的索引值
newCapacity |= newCapacity >>> 1;
newCapacity |= newCapacity >>> 2;
newCapacity |= newCapacity >>> 4;
newCapacity |= newCapacity >>> 8;
newCapacity |= newCapacity >>> 16;
newCapacity ++; // 这段其实也很有意思, 其实是为了计算新的数组的容量, 会变成下一个档位的2的次方大小,
// 比如 1->2 2->4 3->4 4->8 5->8 6->8 7->8 8->16 18->32
Object[] newArray = Arrays.copyOf(oldArray, newCapacity); // 将老的数据往新的数组进行拷贝
Arrays.fill(newArray, oldCapacity, newArray.length, UNSET); // 将新的多出来的部分,设置占位符
newArray[index] = value; // 将index对应的值设置完
indexedVariables = newArray; // 将新的数组提升成Map中的indexedVariables
}
// 根据当前的 Thread 索引, 获取 Object.
// 这个是一次性的, 对应的线程数据会被设置为 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;
}
}
}
InternalThreadLocalMap
使用数组来管理每个线程中的变量.