Netty源码分析----FastThreadLocal-index生成机制详解

SpringBoot+Vue+MySQL 高校学科竞赛平台 完整可运行版(源码+文档) 本项目基于SpringBoot+Vue+MySQL构建高校学科竞赛管理平台,覆盖学生、教师、领队教师、管理员四大角色,实现竞赛发布、报名、刷题、评分、公示等全流程闭环管理。系统架构清晰,技术主流,配套完整源码、数据库脚本、万字论文、开题报告、答辩PPT及部署文档,支持一键运行,适用于毕业设计、课程设计及院系二次开发,真正实现“开箱即用”。 阅读详情

FastThreadLocal index 生成机制详解

问题背景

在 PooledByteBufAllocator 类的构造函数中:

threadCache = new PoolThreadLocalCache(useCacheForAllThreads);

这会调用 PoolThreadLocalCache 父类 FastThreadLocal 的构造函数:

public FastThreadLocal() {
    index = InternalThreadLocalMap.nextVariableIndex();
}

那么这个 index 是怎么来的呢?

核心机制解析

1. nextIndex 静态变量

在 UnpaddedInternalThreadLocalMap 类中定义了一个静态的 AtomicInteger:

class UnpaddedInternalThreadLocalMap {
    static final AtomicInteger nextIndex = new AtomicInteger();
    // ...
}

关键点:

  • nextIndex 是一个静态变量,在整个 JVM 进程中全局共享
  • 使用 AtomicInteger 保证线程安全的自增操作
  • 初始值为 0(AtomicInteger 默认值)

2. nextVariableIndex() 方法

在 InternalThreadLocalMap 类中实现:

public static int nextVariableIndex() {
    int index = nextIndex.getAndIncrement();  // 原子性地获取当前值并自增
    if (index < 0) {
        nextIndex.decrementAndGet();
        throw new IllegalStateException("too many thread-local indexed variables");
    }
    return index;
}

工作流程:

  1. 调用 getAndIncrement() 原子性地获取当前值,并将 nextIndex 加 1
  2. 检查是否溢出(index < 0 表示超过 Integer.MAX_VALUE)
  3. 如果溢出,回退并抛出异常
  4. 返回获取到的 index 值

3. FastThreadLocal 构造函数

public class FastThreadLocal<V> {
    // 第一个 FastThreadLocal 实例会占用 index = 0
    private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();
    
    private final int index;  // 每个实例的唯一索引
    
    public FastThreadLocal() {
        index = InternalThreadLocalMap.nextVariableIndex();
    }
}

完整的 index 分配流程

示例场景

假设我们创建多个 FastThreadLocal 实例:

// 第一次:FastThreadLocal 类加载时
// variablesToRemoveIndex = nextIndex.getAndIncrement() = 0
// nextIndex 变为 1

// 创建第一个 FastThreadLocal 实例
FastThreadLocal<String> ftl1 = new FastThreadLocal<>();
// ftl1.index = nextIndex.getAndIncrement() = 1
// nextIndex 变为 2

// 创建第二个 FastThreadLocal 实例
FastThreadLocal<Integer> ftl2 = new FastThreadLocal<>();
// ftl2.index = nextIndex.getAndIncrement() = 2
// nextIndex 变为 3

// 创建 PoolThreadLocalCache(继承自 FastThreadLocal)
PoolThreadLocalCache cache = new PoolThreadLocalCache(true);
// cache.index = nextIndex.getAndIncrement() = 3
// nextIndex 变为 4

index 分配表

实例index 值说明
FastThreadLocal.variablesToRemoveIndex0类加载时分配,用于存储需要清理的 FastThreadLocal 列表
第一个 FastThreadLocal 实例1第一个用户创建的实例
第二个 FastThreadLocal 实例2第二个用户创建的实例
PoolThreadLocalCache 实例3PooledByteBufAllocator 中的 threadCache
……依次递增

index 的作用

1. 作为数组索引

每个线程都有一个 InternalThreadLocalMap,其中包含一个 Object[] 数组:

class UnpaddedInternalThreadLocalMap {
    Object[] indexedVariables;  // 存储线程本地变量的数组
}

index 就是这个数组的索引位置:

public Object indexedVariable(int index) {
    Object[] lookup = indexedVariables;
    return index < lookup.length ? lookup[index] : UNSET;
}

public boolean setIndexedVariable(int index, Object value) {
    Object[] lookup = indexedVariables;
    if (index < lookup.length) {
        Object oldValue = lookup[index];
        lookup[index] = value;  // 使用 index 作为数组索引
        return oldValue == UNSET;
    } else {
        expandIndexedVariableTableAndSet(index, value);
        return true;
    }
}

2. 快速访问

通过 index 直接访问数组元素,时间复杂度为 O(1),比 JDK 的 ThreadLocal 使用哈希表更快。

关键设计要点

1. 全局唯一性

  • nextIndex 是静态变量,保证每个 FastThreadLocal 实例都有唯一的 index
  • 即使在不同线程中创建,index 也是全局递增的

2. 线程安全

  • 使用 AtomicInteger 保证多线程环境下的安全自增
  • 无需额外的同步机制

3. 空间换时间

  • 每个线程维护一个数组,空间开销较大
  • 但访问速度极快,适合高性能场景

4. 动态扩容

private void expandIndexedVariableTableAndSet(int index, Object value) {
    Object[] oldArray = indexedVariables;
    final int oldCapacity = oldArray.length;
    int newCapacity = index;
    // 使用位运算计算新容量(向上取到最近的 2 的幂次)
    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;
}

总结

FastThreadLocal 的 index 生成机制:

  1. 全局计数器:使用静态的 AtomicInteger nextIndex 作为全局计数器
  2. 原子自增:每次创建 FastThreadLocal 实例时,调用 getAndIncrement() 获取唯一索引
  3. 数组索引:index 用作每个线程的 indexedVariables 数组的索引位置
  4. 高性能访问:通过数组索引直接访问,避免哈希计算和冲突处理
ISA-95(S95)标准详解 ISA-95是制造业系统集成的“通用语言”,通过分层模型和信息流规范,打通企业计划层与设备控制层,成为实现数字化工厂的核心标准之一。其与ISA-88的协同应用,可进一步优化生产执行与资源管理的效率。标准,旨在解决企业商业系统(如ERP)与工业控制系统(如MES、SCADA)之间的集成问题。 阅读详情

相关推荐

微前端实战:MicroApp内存泄漏优化策略与性能调优

本文分享了在大型后台管理系统微前端化过程中,使用MicroApp框架时遇到的内存泄漏实战问题与优化策略。通过深入分析沙箱机制,提出动态加载、精准卸载、沙箱配置优化及第三方库补丁等核心方案,并结合Vue/React子应用专项检查清单,有效解决了内存占用飙升问题,为微前端架构的性能调优提供了系统性解决方案。

weixin_29014939的博客 284

Netty 4.2.x 源码深度解析 (二):FastThreadLocal —— Netty 自研线程局部变量

本文针对 JDK ThreadLocal 哈希冲突、内存泄漏、计算开销大等痛点,解析 Netty 4.2.x 自研的 FastThreadLocal 实现。其通过全局递增索引 + 数组存储实现无冲突 O (1) 存取,依托 InternalThreadLocalMap 完成数据读写与扩容。借助 FastThreadLocalThread 实现快速访问路径,搭配 FastThreadLocalRunnable 自动清理变量,规避线程池内存泄漏,同时适配虚拟线程,兼顾高性能与内存安全。

于云原生深处,追寻架构与代码的优雅 517

机器人导航学习历程(四)local planner

local planner   我们先来回顾一下Navigation的框架,可以看出位于红框中的local_planner是move_base节点的一部分,输入包括来自global_planner的全局的规划路径、里程计信息以及local_costmap的信息,输出是速度控制指令,作为控制器的输入。 base_local_planner   局部规划一般是用base_local_planner包...

yuniruchujian的博客 4413

Netty源码分析---FastThreadLocal

FastThreadLocal实现原理  FastThreadLocal是JDK中ThreadLocal的扩充,通过对重建FastThreadLocal的线程建立索引的方式来存储线程本地变量。get set值的过程中根据整形索引index实现线程本地变量的快速访问。通过index索引访问线程本地变量具有比ThreadLocal通过ThreadLocalMap访问线程变量更快的效率。  Thread...

凌霄的专栏 449

从科研小白到动物行为分析:我的DeepLabCut 3.0安装与初体验全记录

本文记录了从科研小白到成功安装并使用DeepLabCut 3.0进行动物行为分析的全过程。详细介绍了Anaconda环境配置、CUDA版本选择、DeepLabCut安装步骤及验证方法,并分享了初体验中的实用技巧和跨学科研究心得,为生物研究者提供了AI工具应用的实战指南。

weixin_30235225的博客 402

[LVGL] 刷新率优化

实验硬件:STM32F407ZGT6;2.4寸TFT-LCD模块(ILI9341驱动芯片、XTP2046触摸芯片)本文目标:lvgl的刷新率优化,解决拉帘子问题注意:本文在LVGL显示触摸代码移植完成的基础上进行,第一次使用lvgl可根据前文一步步移植,点击下方传送门查看相关文章传送门:STM32F4驱动ILI9341的TFT-LCD触摸屏(HAL库)(一)STM32F4驱动ILI9341的TFT-LCD触摸屏(HAL库)(二)[LVGL] 显示代码移植 基于STM32F4。

2301_77117901的博客 2784

InnoDB 内存结构总览:Change Buffer、AHI 与 Log Buffer

本文系统梳理InnoDB内存结构中的ChangeBuffer、Adaptive Hash Index(AHI)与LogBuffer。ChangeBuffer缓存二级索引页不在内存时的变更,减少随机IO,仅在页加载时合并;聚簇索引修改立即执行,因数据本身不可延后。AHI基于高频等值查询自动构建哈希索引,加速定位,仅支持等值操作。LogBuffer为redo log内存缓冲,配合磁盘日志实现崩溃恢复。三者均服务于性能优化,其中ChangeBuffer与AHI共享BufferPool空间,而LogBuffer独立

bksczm的博客 298

TC387 MCMCAN Message RAM配置详解:Tx Buffer与Rx FIFO地址布局

在嵌入式CAN/CAN FD通信系统中,缓冲区和FIFO是数据收发的核心机制,而AURIX TC3xx系列单片机将这一机制集成在了MCMCAN模块专用的Message RAM中。这是一块由CAN控制器独占的内存区域,开发人员需要按照寄存器规范手动划分Tx Buffer、Rx FIFO、过滤元素等子区间。合理的RAM布局能确保不同功能区域互不重叠、有序排列,避免数据覆盖与错帧。通过掌握TXBC、RXF0C等配置寄存器的字段含义,结合实用的地址布局表,可以显著降低多节点CAN通信的调试成本。本内容面向使用TC3

weixin_34226182的博客 224

信创环境下PageOffice文档控件适配与实践

信创适配做到文档控件这一层,拼的已经不是"有没有国产版本",而是同一个功能在两类终端上是否真的等价。等价的标准很具体:同一次点击能得到同样的结果,同一份公文能得到同样的版式,同一个项目不需要维护两套代码。这背后是三件并不轻松的工作:服务端用一套接口同时支撑两类终端,客户端把两种系统与四种芯片的安装包分发清楚,文档内核层由产品侧跟着 WPS 的版本走。浏览器这一层的压力,则被收进了产品自己的窗口里——升级节奏由产品掌握,不再交给运气。

zi_wu_xian的专栏 327

《Python星球日记》 第73天:情感分析与主题建模

《Python星球日记》 第73天:情感分析与主题建模,今天我们将探索两个自然语言处理领域的重要技术:情感分析和主题建模。这两项技术在社交媒体分析、用户反馈处理、市场研究等多个领域有着广泛应用。

Code_流苏:在代码中寻诗意,在实践中觅真知 919

【优化求解】基于matlab粒子群算法PSO确定最佳开关角对称级联多层逆变器【含Matlab源码 13080期】

粒子群算法PSO确定最佳开关角对称级联多层逆变器 完整代码,包运行;可提供运行操作视频!适合小白!

订阅付费专栏Matlab(奶茶价版),可赠送奶茶价版付费专栏指定代码1份; 97

第三篇 第 6 课

前置:第三篇第 1 课(stdx 引入),第二篇第 1 课(std.regex)。环境:仓颉 SDK 1.2.0。本文所有代码与输出均逐行实测。

weixin_41618057的博客 516

FISCO BCOS 系列(一)—— 搭建第一个区块链网络&配置控制台指南

本文详细介绍了FISCO BCOS区块链网络的搭建与配置过程,包括环境准备、单机四节点网络搭建、控制台配置使用等核心内容。从系统要求、依赖安装开始,逐步指导如何通过脚本快速搭建区块链网络,配置控制台连接,并演示了账户管理、合约部署调用等基础操作。同时提供了多节点网络配置、常见问题解决方案以及生产环境安全建议,为开发者提供了从入门到进阶的完整指南。

分享AI、区块链技术及应用,未来已来 812

V8 机制、手写核心函数与 TypeScript 类型体操

或固定初始化(如数组先定长、对象先给全字段)保持类型与形状稳定;这些都比"换框架"更基础。只能处理纯数据(丢函数、Date、RegExp、循环引用报错)。生产级深拷贝要处理:原始值短路、循环引用、V8(Chrome / Node 的 JS 引擎)不是"解释一行跑一行"那么简单,它用。图:V8 执行流程——解释执行 + 热点优化,优化失败会 Deopt 回退。JS 内存自动管理,但"自动"不等于"不会漏"。是"固定间隔最多执行一次"。手写 Promise 是"懂异步"的试金石。是"停下后才执行最后一次",

qq_38468358的博客 351

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

【从零理解 Spring AI · 12】MCP 的两种角色:做客户端还是做服务端

上一篇讲了 MCP 的概念:标准协议、三大角色、M+N 替代 M×N。

nice_lcj520的博客 538

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Java 集合容器高频面试题全解:HashMap 树化阈值、1.7 死循环与 ConcurrentHashMap 演进(2026 招聘 JD 真题复盘)

HashMap 树化阈值 8 的泊松分布依据、退化阈值 6 的防抖设计、JDK 1.7 头插成环死循环的排查与修复、1.8 尾插后为何仍线程不安全、ConcurrentHashMap 放弃分段锁的原因与 ForwardingNode 协作扩容、computeIfAbsent 死锁陷阱、大集合找重复的场景题选型,附三层追问链自测。题目来源为 38 期公开招聘 JD 样本与字节、拼多多、建行、美团、快手公开面经。

蒙眼过河 420

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

spdlog 同步日志库使用详解

spdlog是一个轻量级 C++ 日志库,支持同步日志、异步日志、多线程日志、日志文件轮转和自定义日志格式。对于嵌入式 Linux 应用开发,我建议先使用。它可以帮我们完成:日志级别过滤。时间戳和线程 ID 输出。日志格式化。终端和文件输出。多线程安全写入。日志文件按大小或时间轮转。我们不需要自己实现互斥锁、文件写入、日志格式化和轮转等底层功能。

zengjiajun2006的博客 1120

JavaSE通关手册:数据类型与变量

代码无需额外处理,编译时编译器自动完成转换。

xys_678的博客 221

Java 多态 学习笔记

多态是面向对象编程的重要特性,指同一操作作用于不同对象时产生不同行为。其核心在于“父类引用指向子类对象”,结合方法重写实现运行时动态绑定。多态使代码更灵活、可扩展,如用Person p = new Student();统一处理各类人员注册,无需修改调用逻辑。但多态无法直接调用子类特有方法,需通过instanceof判断并强制转换。编译时看左边(类型),运行时看右边(实际对象),实现解耦与维护便利。

AA_AA114514的博客 367

IDEA 简介:从零认识 IntelliJ IDEA

IDEA 全称,是由 JetBrains 公司开发的一款主流 Java 集成开发环境(IDE)。它集代码编辑、编译、调试、测试、版本控制、构建管理等功能于一体,被大量 Java 开发者视为日常开发的首选工具。所谓 IDE(Integrated Development Environment,集成开发环境),就是把写代码所需的各类工具整合到同一个界面中。相比只用文本编辑器加命令行编译,IDE 能显著减少重复操作,让开发者把精力集中在业务逻辑上。

ztI10的博客 174

Java实现批量线段相交检测(跨积判定+扫描线优化与踩坑复盘)

【代码】Java实现批量线段相交检测(跨积判定+扫描线优化与踩坑复盘)

m0_64476639的博客 341

c++ explicit关键字详解

explicit。

拒绝AI文,努力在AI时代写出感动人心的好文章 152

ubuntu安装hadoop系统

本文详细介绍了基于VMware克隆虚拟机搭建三节点Hadoop分布式集群的全过程:使用同一Ubuntu镜像克隆出master、worker1、worker2三台虚拟机,依次配置主机名、固定IP(如192.168.82.10/11/12)、SSH服务及免密登录,确保节点间网络互通。随后安装Java,下载配置Hadoop并分发至各节点,最终初始化启动集群,验证其存储与计算功能,实现高效的大数据环境部署。

qq_43592674的博客 350

TRingBuffer两端都能增删(快递站版)

TRingBuffer 是一个支持两端增删、下标访问且容量动态增长的环形双端队列。它通过无符号索引的永不归零设计,利用减法自动模运算实现空满判断与元素计数,避免了传统环形缓冲浪费格子的问题。内部以票号(索引)标记首尾,扩容时重排元素为连续存储,保证 O(1) 操作与高缓存效率。虽不线程安全,但其高效性使其成为游戏开发中事件队列、命令缓冲等场景的理想选择。

u013768914的博客 310

Mac上装了最新版本的Android Studio,但是没找到jdk的设置选项也没找到jbr的目录

新版Android Studio(2025.3.1+)因三项变更导致常见问题:一、JDK设置移至“DaemonJVM criteria”,新项目默认自动探测或下载JDK;二、JBR目录改名为带版本号的jbr-21等,需进入.app/Contents/查看,或通过About窗口确认运行时;三、命令行缺adb因platform-tools未加入PATH,需在SDK Manager中勾选并配置~/.zshrc中的ANDROID_HOME及PATH。重装或清理残留可解决缺失问题,切勿手动设JAVA_HOME或安装冲

Programming is a highly artistic endeavor 381

Java Arrays.asList 常见坑详解|UnsupportedOperationException、数组联动、基本类型 bug

解析 Arrays.asList 常见开发陷阱,演示 UnsupportedOperationException、底层数组引用共享、基本类型数组问题,区分 Arrays 内部 ArrayList 与 java.util.ArrayList,给出数组转 List 的各种场景正确代码。

weixin_42617033的博客 495
上一篇: Netty源码分析---Reactor线程模型深度解析(二)
下一篇: Netty源码解析---FastThreadLocal-addToVariablesToRemove方法详解
不早睡不改名@
博客等级 码龄5年 536粉丝 306原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值