当前位置: 首页 > news >正文

Netty中InternalThreadLocalMap的作用

io.netty.util.internal.InternalThreadLocalMap 是 Netty 内部工具类,用于管理高效的线程局部存储(Thread-Local Storage)。它替代了 Java 标准库的 ThreadLocal,为 Netty 的高性能异步框架提供了优化的线程局部变量管理机制。该类在 Netty 的运行时环境中扮演关键角色,特别是在事件循环(EventLoop)、对象池(Recycler)、随机数生成和其他性能敏感场景中。

  • 作用
    • 提供高效的线程局部存储,管理每个线程的独立数据(如缓存、计数器、上下文)。
    • 优化 ThreadLocal 的性能,减少内存分配和访问开销。
    • 支持 Netty 的核心功能模块,如 FastThreadLocal、对象池(Recycler)、随机数生成(ThreadLocalRandom)、ChannelHandler 共享性检查等。

源码注释

/*** InternalThreadLocalMap 是 Netty 的线程局部存储管理类,用于高效存储线程特定数据。* 每个线程拥有一个唯一的 InternalThreadLocalMap 实例,通过 ThreadLocal 或 FastThreadLocalThread 访问。* 支持 FastThreadLocal、对象池、随机数生成等功能。*/
public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {/*** 慢路径的 ThreadLocal,用于普通线程存储 InternalThreadLocalMap。*/private static final ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = new ThreadLocal<InternalThreadLocalMap>();/*** 用于分配线程局部变量的索引,递增生成唯一索引。*/private static final AtomicInteger nextIndex = new AtomicInteger();/*** 表示未设置的占位符对象。用于区分未设置值和值为null*/public static final Object UNSET = new Object();/*** 存储线程局部变量的数组,使用索引访问。*/private Object[] indexedVariables;// 核心字段//在 Netty 中,Future 对象可以添加多个监听器(FutureListener),当 Future 完成时,会通知所有添加的监听器。如果在监听器的 operationComplete 方法   中又触发了另一个 Future 的完成,并且这个新的 Future 也有监听器,就会形成递归调用。如果递归深度过深,就可能导致 StackOverflowError。//futureListenerStackDepth 字段用于记录当前线程中 Future 监听器通知的递归深度。Netty 通过配置一个最大递归深度(通过系统属性   io.netty.defaultPromise.maxListenerStackDepth 配置,默认值为 8),当递归深度超过这个最大值时,Netty 会将后续的监听器通知任务放到事件循环中异步执行,而不是继续在当前栈中递归调用,从而避免栈溢出。private int futureListenerStackDepth;//在 Netty 的本地传输中,当一个 LocalChannel 读取数据时,可能会触发一系列的操作,这些操作可能会递归调用读取逻辑。如果递归深度过深,就可能导致 StackOverflowError。localChannelReaderStackDepth 字段可以记录当前线程中 LocalChannel 读取操作的递归深度,当递归深度超过一定阈值时,可以采取相应的措施来避免栈溢出。private int localChannelReaderStackDepth; // Channel 读取栈深度//handlerSharableCache 把类和其对应的是否可共享的布尔值映射起来。当首次判断某个 ChannelHandler 类是否可共享时,会进行反射操作并把结果存入缓存;后续再判断同一类时,直接从缓存获取结果,无需再次反射,提高了判断效率。private Map<Class<?>, Boolean> handlerSharableCache; // ChannelHandler 共享缓存private IntegerHolder counterHashCode; // 计数器哈希码private ThreadLocalRandom random; // 线程局部随机数生成器//TypeParameterMatcher 用于判断一个对象是否是特定类型或其子类型,常用于处理消息类型匹配的场景。当需要判断某个对象是否为特定类型时,会使用 TypeParameterMatcher 来进行匹配。private Map<Class<?>, TypeParameterMatcher> typeParameterMatcherGetCache; // 类型匹配缓存private Map<Class<?>, Map<String, TypeParameterMatcher>> typeParameterMatcherFindCache; // 类型查找缓存/*** 获取当前线程的 InternalThreadLocalMap 实例。* @return 当前线程的 InternalThreadLocalMap*/public static InternalThreadLocalMap get() {Thread thread = Thread.currentThread();if (thread instanceof FastThreadLocalThread) {return fastGet((FastThreadLocalThread) thread);} else {return slowGet();}}/*** 适用于 FastThreadLocalThread 类型的线程。FastThreadLocalThread 是 Netty 自定义的线程类,它内部维护了一个 InternalThreadLocalMap 实      *  例,通过 threadLocalMap() 方法可以直接获取该实例。*/private static InternalThreadLocalMap fastGet(FastThreadLocalThread thread) {InternalThreadLocalMap threadLocalMap = thread.threadLocalMap();if (threadLocalMap == null) {thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());}return threadLocalMap;}/*** 适用于普通的 Thread 类型的线程。对于普通线程,没有内置的 InternalThreadLocalMap 实例,因此需要使用 Java 标准的 ThreadLocal 来存储和获取      * InternalThreadLocalMap 实例。*/private static InternalThreadLocalMap slowGet() {InternalThreadLocalMap ret = slowThreadLocalMap.get();if (ret == null) {ret = new InternalThreadLocalMap();slowThreadLocalMap.set(ret);}return ret;}/*** 构造函数,初始化 indexedVariables 数组。*/private InternalThreadLocalMap() {super(newIndexedVariableTable());}/*** 创建初始大小为 32 的线程局部变量数组,填充 UNSET。* @return 初始化后的数组*/private static Object[] newIndexedVariableTable() {Object[] array = new Object[32];Arrays.fill(array, UNSET);return array;}/*** 分配一个新的线程局部变量索引。* @return 唯一索引* @throws IllegalStateException 如果索引溢出*/public static int nextVariableIndex() {int index = nextIndex.getAndIncrement();if (index < 0) {nextIndex.decrementAndGet();throw new IllegalStateException("too many thread-local indexed variables");}return index;}/*** 获取指定索引的线程局部变量值。* @param index 变量索引* @return 变量值,或 UNSET 如果未设置*/public Object indexedVariable(int index) {Object[] lookup = indexedVariables;return index < lookup.length ? lookup[index] : UNSET;}/*** 设置指定索引的线程局部变量值。* @param index 变量索引* @param value 要设置的值* @return true 如果是首次设置,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;}}/*** 扩展 indexedVariables 数组以支持更大的索引,并设置值。* @param index 变量索引* @param value 要设置的值*/private void expandIndexedVariableTableAndSet(int index, Object value) {Object[] oldArray = indexedVariables;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;}
}

3. 作用与功能

InternalThreadLocalMap 是 Netty 的线程局部存储核心,其主要作用包括:

  1. 高效线程局部存储

    • 使用数组(indexedVariables)存储线程局部变量,通过索引访问,性能优于 Java ThreadLocalHashMap 实现。
    • 支持 FastThreadLocal,Netty 的高性能 ThreadLocal 替代品,通过 nextVariableIndex 分配唯一索引。
  2. 支持 Netty 功能模块

    • 对象池(Recycler):存储对象池的上下文数据,减少对象分配开销(如 ByteBuf 缓存)。
    • 随机数生成random 字段提供线程局部的 ThreadLocalRandom 实例。
    • ChannelHandler 共享性handlerSharableCache 缓存 @Sharable 状态,优化 ChannelPipeline 处理。
    • 类型匹配缓存typeParameterMatcherGetCachetypeParameterMatcherFindCache 减少反射开销。
    • 栈深度跟踪futureListenerStackDepthlocalChannelReaderStackDepth 防止递归调用溢出。
  3. 性能优化

    • 快速路径:对于 FastThreadLocalThread(Netty 自定义线程类),直接存储和访问 InternalThreadLocalMap,避免 ThreadLocal 的开销。
    • 慢路径:对于普通线程,使用 ThreadLocal 存储,保持兼容性。
    • 数组存储:初始大小为 32 的数组,动态扩展,减少哈希操作。
  4. 线程隔离

    • 确保每个线程的 InternalThreadLocalMap 独立,避免数据干扰。
    • 特别适合 Netty 的单线程 EventLoop 模型。

4. 关键方法解析

以下是 InternalThreadLocalMap 的核心方法及其作用:

4.1 get
  • 签名public static InternalThreadLocalMap get()
  • 作用:获取当前线程的 InternalThreadLocalMap 实例。
  • 逻辑
    • 检查线程是否为 FastThreadLocalThread
      • 如果是,调用 fastGet 直接访问。
      • 否则,调用 slowGet 使用 ThreadLocal
    • 如果实例不存在,创建并存储。
  • 使用场景FastThreadLocal 和其他模块通过 get 获取线程局部存储。
4.2 nextVariableIndex
  • 签名public static int nextVariableIndex()
  • 作用:分配唯一索引,用于 FastThreadLocal 变量存储。
  • 逻辑
    • 使用 AtomicInteger 递增生成索引。
    • 防止索引溢出(负数时抛异常)。
4.3 indexedVariable
  • 签名public Object indexedVariable(int index)
  • 作用:获取指定索引的线程局部变量值。
  • 逻辑
    • 如果索引在数组范围内,返回值;否则返回 UNSET
4.4 setIndexedVariable
  • 签名public boolean setIndexedVariable(int index, Object value)
  • 作用:设置指定索引的线程局部变量值。
  • 逻辑
    • 如果索引在数组范围内,设置值并返回是否首次设置。
    • 如果索引超出范围,扩展数组并设置值。
4.5 expandIndexedVariableTableAndSet
  • 签名private void expandIndexedVariableTableAndSet(int index, Object value)
  • 作用:扩展 indexedVariables 数组以支持更大索引。
  • 逻辑
    • 使用位运算计算新容量(接近 2 的幂)。
    • 复制旧数组,填充新部分为 UNSET,设置指定索引的值。

5. 与 EventLoop 的关系

InternalThreadLocalMap 在 Netty 的事件循环(EventLoop)模型中发挥重要作用:

  1. 线程隔离

    • 每个 EventLoop(如 NioEventLoop)绑定一个线程,InternalThreadLocalMap 为该线程提供独立的存储空间。
    • 示例:NioEventLoop 使用 InternalThreadLocalMap 存储事件循环的上下文数据。
  2. 性能优化

    • EventLoop 线程通常是 FastThreadLocalThread,通过 fastGet 直接访问 InternalThreadLocalMap,减少开销。
    • 示例:在 NioEventLoop#run 方法中,FastThreadLocal 可能用于存储临时状态。
  3. 支持异步操作

    • InternalThreadLocalMap 的字段(如 futureListenerStackDepth)用于跟踪 ChannelFuture 监听器的调用栈深度,防止递归溢出。
    • 示例:在 ChannelPipeline 的事件处理中,handlerSharableCache 优化 ChannelHandler 的共享性检查。
  4. 对象池支持

    • EventLoop 线程使用 InternalThreadLocalMap 管理对象池(如 Recycler),提高 ByteBuf 等对象的复用效率。

6. 使用场景

InternalThreadLocalMap 在 Netty 中的具体应用包括:

  1. FastThreadLocal 存储

    • 支持 FastThreadLocal,Netty 的高性能 ThreadLocal 实现。
    • 示例:ByteBufRecycler 使用 FastThreadLocal 存储对象池上下文。
  2. 对象池(Recycler)

    • 管理线程局部的对象池实例,减少内存分配。
    • 示例:PooledByteBufAllocator 使用 InternalThreadLocalMap 缓存 ByteBuf
  3. 随机数生成

    • random 字段提供线程局部的 ThreadLocalRandom 实例。
    • 示例:负载均衡或随机选择 EventLoop
  4. ChannelHandler 共享性

    • handlerSharableCache 缓存 ChannelHandler@Sharable 状态。
    • 示例:ChannelPipeline 检查 ChannelHandler 是否可共享。
  5. 类型匹配优化

    • typeParameterMatcherGetCachetypeParameterMatcherFindCache 缓存类型匹配结果,减少反射开销。
    • 示例:ChannelHandler 的类型检查。
http://www.dtcms.com/a/304614.html

相关文章:

  • Rust实现GPU驱动的2D渲染引擎
  • Vue3 学习教程,从入门到精通, Vue3 自定义指令语法知识点及案例(20)
  • c++ nlohmann/json读写json文件
  • JavaWeb学习打卡18(JDBC案例详解)
  • ansible 使用更高版本的python版本
  • Python中的决策树机器学习模型简要介绍和代码示例(基于sklearn)
  • 【牛客网C语言刷题合集】(五)——主要二进制、操作符部分
  • GO 开发环境安装及配置
  • Claude Code 使用教程(对接智谱模型)
  • 84、【OS】【Nuttx】【启动】栈溢出保护:asm 关键字(下)
  • SpringBoot集成Quzrtz实现定时任务
  • 【目标检测】小样本度量学习
  • 记录一个TI DSP编译器的Bug
  • CentOS安装ffmpeg并转码视频为mp4
  • 预过滤环境光贴图制作教程:第四阶段 - Lambert 无权重预过滤(Stage 3)
  • 预过滤环境光贴图制作教程:第一步 - HDR 转立方体贴图
  • Android Compose 自定义组件完全指南
  • 对College数据进行多模型预测(R语言)
  • 《React与Vue构建TODO应用的深层逻辑》
  • 【lucene】SegmentCoreReaders
  • linux_前台,后台进程
  • LeetCode热题100——155. 最小栈
  • (LeetCode 面试经典 150 题) 150. 逆波兰表达式求值 (栈)
  • 电脑主机显示的python版本是3.8.6,但是我在控制面板没有找到,想删除不知道怎么操作怎么办
  • 《 java 随想录》| LeetCode链表高频考题
  • 【LeetCode】大厂面试算法真题回忆(111)--身高排序
  • 鱼皮项目简易版 RPC 框架开发(五)
  • 2.oracle保姆级安装教程
  • 逐渐走进Ai世界~
  • Django模型开发:模型字段、元数据与继承全方位讲解