FastThreadLocal 原理解析
FastThreadLocal

- 每个 FastThread 包含一个 FastThreadLocalMap,每个 FastThreadLocalThread 中的多个 FastThreadLocal 占用不同的索引。
- 每个 InternalThreadLocalMap 的第一个元素保存了所有的 ThreadLocal 对象。之后的元素保存了每个 ThreadLocal 对应的 value
基本操作
get()
当前线程中
- 找到 ThreadLocal 的 index,value 加入 InternalThreadLocalMap 对应索引的位置
set()
当前线程中
- 找到 ThreadLocal 的 index,value 加入 InternalThreadLocalMap 对应索引的位置
- 将 ThreadLocal 加入当前线程 InternalThreadLocalMap 的第一个元素对应的集合
remove()
当前线程中
- 找到 ThreadLocal 的 index,InternalThreadLocalMap 中 index 对应的 value 置为 UNSET
- 将 ThreadLocal 从当前线程 InternalThreadLocalMap 的第一个元素集合中删除
关键设计点
兼容 ThreadLocal
当线程没有使用 FastThreadLocal 的时候,默认走 ThreadLocal 的逻辑。
初始大小
初始大小为 32
hash 算法
直接使用全局的自增,不存在Hash 冲突,以空间换时间
扩容条件是什么?如何扩容?
- 扩容条件:当前线程元素超出容量
- 扩容:元素数量扩展为向上取最近 2 次幂整数,比如,5 取8,31 取 64。
public boolean setIndexedVariable(int index, Object value) {Object[] lookup = indexedVariables;// index 大于容量if (index < lookup.length) {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;final int oldCapacity = oldArray.length;int newCapacity;// 当小于 2的30次方时,容量扩展为向上取最近 2 次幂整数,比如,5 取8,31 取 64。if (index < ARRAY_LIST_CAPACITY_EXPAND_THRESHOLD) {newCapacity = index;newCapacity |= newCapacity >>> 1;newCapacity |= newCapacity >>> 2;newCapacity |= newCapacity >>> 4;newCapacity |= newCapacity >>> 8;newCapacity |= newCapacity >>> 16;newCapacity ++;} else {newCapacity = ARRAY_LIST_CAPACITY_MAX_SIZE;}Object[] newArray = Arrays.copyOf(oldArray, newCapacity);Arrays.fill(newArray, oldCapacity, newArray.length, UNSET);newArray[index] = value;indexedVariables = newArray;}
如何防止内存泄漏
自动: 使用ftlt执行一个被FastThreadLocalRunnable wrap的Runnable任务,在任务执行完毕后会自动进行ftl的清理。
final class FastThreadLocalRunnable implements Runnable {private final Runnable runnable;private FastThreadLocalRunnable(Runnable runnable) {this.runnable = ObjectUtil.checkNotNull(runnable, "runnable");}@Overridepublic void run() {try {runnable.run();} finally {FastThreadLocal.removeAll();}}static Runnable wrap(Runnable runnable) {return runnable instanceof FastThreadLocalRunnable ? runnable : new FastThreadLocalRunnable(runnable);}
}
手动: ftl和InternalThreadLocalMap都提供了remove方法,在合适的时候用户可以(有的时候也是必须,例如普通线程的线程池使用ftl)手动进行调用,进行显示删除。
使用
final class FastThreadLocalRunnable implements Runnable {private final Runnable runnable;private FastThreadLocalRunnable(Runnable runnable) {this.runnable = (Runnable)ObjectUtil.checkNotNull(runnable, "runnable");}public void run() {try {this.runnable.run();} finally {// 如果用的是 FastThreadLocalRunnable ,默认会做清理FastThreadLocal.removeAll();}}static Runnable wrap(Runnable runnable) {return (Runnable)(runnable instanceof FastThreadLocalRunnable ? runnable : new FastThreadLocalRunnable(runnable));}
}
存在什么问题
1、空间浪费,所有线程的 ThreadLocalMap 数组大小是一样的
比如,线程1 创建 100 个 ThreadLocal 对象。线程 1 里面有一个长度为 100 的数组。
此时,第二个线程需要调用 ThreadLocal 100 的 get 方法,第二个线程需要分配 100 个 Object 对象。
import io.netty.util.concurrent.FastThreadLocal;
import io.netty.util.concurrent.FastThreadLocalThread;import java.util.ArrayList;
import java.util.List;public class FastThreadLocalTest {private List<FastThreadLocal<String>> fastThreadLocals = new ArrayList<>();private List<ThreadLocal<String>> threadLocals = new ArrayList<>();void thread1Init() {new Thread (() -> {for (int i = 0; i < 31; i++) {ThreadLocal<String> threadLocal = new ThreadLocal<>();threadLocal.get();threadLocals.add(threadLocal);}}).start();}void thread2Init() {new Thread(() -> {threadLocals.get(threadLocals.size() - 1).get();});}void fastThread1Init() {new FastThreadLocalThread (() -> {for (int i = 0; i < 33; i++) {FastThreadLocal<String> fastThreadLocal = new FastThreadLocal<>();fastThreadLocal.get();fastThreadLocals.add(fastThreadLocal);}}).start();}void fastThread2Init() {new FastThreadLocalThread(() -> {fastThreadLocals.get(fastThreadLocals.size() - 1).get();});}public static void main(String[] args) {FastThreadLocalTest test = new FastThreadLocalTest();test.fastThread1Init();test.fastThread2Init();test.thread1Init();test.thread2Init();}
}
2、FastThreadLocal 需要配套 FastThreadLocalThread 使用,不然还不如原生 ThreadLocal。
3、FastThreadLocal 使用最好配套 FastThreadLocalRunnable,这样执行完任务后会主动调用 removeAll 来移除所有
性能压测
netty 官方 mincrobench
相关文章:
FastThreadLocal 原理解析
FastThreadLocal 每个 FastThread 包含一个 FastThreadLocalMap,每个 FastThreadLocalThread 中的多个 FastThreadLocal 占用不同的索引。每个 InternalThreadLocalMap 的第一个元素保存了所有的 ThreadLocal 对象。之后的元素保存了每个 ThreadLocal 对应的 value …...
设计模式B站学习(一)(java)
这里写目录标题 一、设计模式概述1.1 软件设计模式的产生背景1.2 软件设计模式的概念1.3 学习设计模式的必要性1.4 设计模式分类 二、UML图2.1 类图概述2.2 类图的作用2.3 类图表示法2.3.1 类图表示方法2.3.2 类与类之间关系的表示方法2.3.2.1 关联关系2.3.2.2 聚合关系2.3.2.3…...
Pandas如何轻松按位置删除多重索引列?
在Pandas处理DataFrame数据的过程中,我们常常需要删除某些不需要的列。那么,如何高效地按位置删除Pandas DataFrame的多重索引列呢? 今天分享在Pandas中按位置删除多重索引列的具体方法: 第一步:获取所有列标签 使用df.columns获取DataFrame的所有列标…...
第五十七天学习记录:C语言进阶:结构体链表的自学
先展示一段代码: #define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h> #include <stdlib.h>// 定义链表节点结构体 typedef struct Node {int value;struct Node* next; } Node;int main() {// 创建链表头指针Node* head (Node*)malloc(sizeof(Node…...
【一次调频】考虑储能电池参与一次调频技术经济模型的容量配置方法(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
ICV报告: 智能座舱SoC全球市场规模预计2025年突破50亿美元
在智能化、互联化车辆需求不断增加的推动下,汽车行业正在经历一场范式转变。这一转变的前沿之一是智能座舱SoC。本市场研究报告对智能座舱SoC市场进行了全面的分析,包括其应用领域、当前状况和主要行业参与者。 智能座舱SoC指的是现代汽车智能座舱系统的…...
在can协议的基础下编写DBC文件,然后使用该DBC文件下发can协议到底盘完整流程
目录 前言一、VectorCANdb下载及安装二、DBC文件的编写1.新建dbc文件2.建立dbc2.1根据CAN协议设置以下的signals2.2设置报文2.3建立报文与信号的关系2.4建立节点 三、编写程序使用UDP通信下发can协议1.查看can口、电脑ip以及端口号2.编写测试程序 前言 最近完成了一个项目&…...
工业传感器有哪些?
工业传感器是指能在工业制造过程能将感受的力、热、光、磁、声、湿、电、环境等被测量转换成电信号输出的器件与装置,在各种化工、机械、汽车等工业场景上都有应用。 工业传感器有哪些? 工业传感器由于不同的特性也被分为多种不同的类别,主要…...
Docker应用部署之Nginx
部署nginx 要求:在docker容器中部署nginx,并通过外部机器访问nginx 步骤: 1.搜索nginx镜像 docker search nginx 2.拉取nginx镜像 docker pull nginx 3.创建容器 #在root目录下创建nginx目录用于存放nginx项目 mkdir ~/nginx cd ~/ng…...
TerminalWorks TSPrint/TSScan/TSWebCam Crack
/ 远程桌面打印软件,TerminalWorks TSPrint Server/Client 从远程服务器打印到本地打印机的 简单方法 TSPrint 为您提供了一个简单的远程桌面打印软件,以及使 Windows 终端服务操作更容易的附加工具。有选择地启用或禁用功能,以便您可以完全…...
如何使用Springboot实现文件上传和下载,并为其添加实时进度条的功能
文件上传和下载是Web开发中非常基础的功能,但在实际开发中,我们经常需要实时显示文件上传或下载的进度。这篇文章将介绍如何使用Springboot实现文件上传和下载,并为其添加实时进度条的功能。 文件上传 添加Maven依赖项 首先,我…...
安装并新建windows下wxwroks7.0 bootrom工程
双击steup.exe 直接next 直接next 选择typical,然后next I accept 安装完成finish 现在双击Workbench 4,新建vxworks7.0工程,会出现下面的情况,因为没有licence 安装licence,将zwrsLicense-vx7-perm.lic粘贴到安装目…...
element-ui表格el-table的使用
先给大家展示一下效果 Table 属性 属性名说明类型可选值默认值data显示的数据array——heightTable 的高度, 默认为自动高度。 如果 height 为 number 类型,单位 px;如果 height 为 string 类型,则这个高度会设置为 Table 的 sty…...
Backtrader官方中文文档:第八章Indicators指标
本文档参考backtrader官方文档,是官方文档的完整中文翻译,可作为backtrader中文教程、backtrader中文参考手册、backtrader中文开发手册、backtrader入门资料使用。 Indicators指标章节目录 指标(Indicator)指标的使用__init__ 对比 next指标在`__init__`阶段的执行过程指标在…...
CAP原则
CAP原则又称CAP定理,指的是在一个分布式系统中,存在Consistency(一致性)、Availability(可用性)、Partition tolerance(分区容错性),三者不可同时保证,最多只…...
【PowerQuery】M语言的使用产品和使用场景
当然PowerQuery的M语言应用场景不只是引用在PowerBI和Excel中,它具有广泛的应用场景。目前我们可以在以下产品的使用场景中应用到M语言。 Excel PowerQuery应用Excel通过M语言可以实现整体数据的清洗和重构。 PowerBI 的PowerQuery应用 PowerBI也是通过M语言来实现数据…...
【Linux】遇事不决,可先点灯,LED驱动的进化之路---1
【Linux】遇事不决,可先点灯,LED驱动的进化之路---1 前言: 一、最简单的LED驱动程序 1.1 字符设备驱动程序框架 1.2 程序实战 1.2.1 驱动程序(led_drive_simple.c) 1.2.2 应用程序(led_test_simple.c…...
hive任务reduce步骤卡在99%原因及解决
我们在写sql的时候经常发现读取数据不多,但是代码运行时间异常长的情况,这通常是发生了数据倾斜现象。数据倾斜现象本质上是因为数据中的key分布不均匀,大量的数据集中到了一台或者几台机器上计算,这些数据的计算速度远远低于平均…...
C++11 -- lambda表达式
文章目录 lamaba表达式的引入lambda表达式语法lamabda达式各部分说明捕获列表说明 lamaba表达式底层原理探索 lamaba表达式的引入 在C11之前,如果我们想对自定义类型Goods排序,可以根据姓名,价格,学号按照从大到小或者从小到大的方式排序,可是,这样我们要写额外写6个相关的仿函…...
【开源项目】银行查询服务的设计和实现
银行查询服务的设计和实现 项目地址github:https://github.com/xl-echo/bankInquiryService项目地址gitee:https://gitee.com/xl-echo/bank-inquiry-service 银行查询服务的设计初衷是:为提供更加便利的查询服务,我们在分布式系…...
Hermes Agent对接Taotoken自定义Provider的配置要点详解
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Hermes Agent对接Taotoken自定义Provider的配置要点详解 1. 理解对接的基本前提 Hermes Agent是一个支持多种大模型提供方的开发工…...
Unity 3D空间智能适配:Fit It 3D实现物理占位与视觉节奏统一
1. 这不是“自动对齐”,而是空间智能调度:Fit It 3D 解决的是3D世界里的真实物理占位问题你有没有在做关卡编辑时,被一堆散落的箱子、木桶、补给箱卡住进度?手动拖拽、缩放、旋转,反复微调——一个角落多出2毫米&#…...
IPD咨询洞察:企业前后端为什么总是拧巴?IPD给出了答案
很多企业有一个共同的困境:执行力不差,但结果总差那么一口气。产品做出来了,却没有竞争力;战略定下来了,却落不到产品上;研发埋头苦干,市场却说卖不动——前端和后端始终拧巴,内耗比…...
国产工控机选型实战:从自主可控到边缘智能的工业应用解析
1. 项目概述:为什么我们需要关注国产工控机?如果你在工厂里负责过自动化产线,或者在能源、交通行业搞过设备监控,大概率遇到过这样的场景:产线上某台核心控制电脑突然蓝屏,或者某个数据采集模块因为电磁干扰…...
AI 大模型未来技术演进方向与应用发展趋势预判
引言:AI 技术快速迭代,未来已来AI 大模型技术正以超乎想象的速度迭代演进,从参数规模扩张到能力提升、从技术架构创新到应用场景拓展、从成本高企到普惠落地,每一次技术突破都在重塑产业格局、改变商业逻辑、影响生活方式。2026 年…...
Java 读写 Excel 公式:从基础到高级的实战总结
做数据处理的朋友应该都遇到过这种场景:需要批量生成带公式的Excel报表,或者读取现有表格中的公式进行二次计算。以前我都是手动在Excel里写公式,后来发现用Java代码来处理更高效,尤其是数据量大的时候。 今天整理一下平时用得比较…...
手把手教你把Windows虚拟内存文件pagefile.sys从C盘挪走,给SSD系统盘腾出几十G空间
彻底解放C盘空间:Windows虚拟内存文件迁移全指南 你是否遇到过这样的场景:刚装完系统时C盘还剩下大半空间,用着用着却突然弹出"磁盘空间不足"的警告?打开资源管理器一看,一个名为pagefile.sys的"巨无霸…...
用PyTorch从零复现PoolFormer:一个用平均池化替代自注意力的视觉Transformer
用PyTorch从零构建PoolFormer:揭秘平均池化如何颠覆视觉Transformer设计 当整个AI社区都在为Transformer的自注意力机制疯狂时,MetaFormer论文却提出了一个令人震惊的发现:模型性能的关键可能不在于复杂的注意力计算,而在于被长期…...
别再死记硬背寄存器了!用Vivado SDK玩转Zynq 7010的GPIO(附MIO/EMIO/中断完整代码)
实战派Zynq 7010开发:从零玩转GPIO控制与中断处理 刚接触Zynq平台的开发者常被复杂的寄存器配置困扰,其实Xilinx提供的驱动库能大幅简化开发流程。本文将带你用Vivado SDK快速实现GPIO控制,避开底层细节直接产出可运行代码。 1. 环境搭建与基…...
AI如何重塑移动App开发:从功能交付到智能服务的范式跃迁
1. 项目概述:当手机App开发不再只是“写代码”,而变成一场数据驱动的智能进化“How AI and ML are Turning the Mobile App Development Industry into a Smart Industry?”——这个标题不是一句空泛的行业口号,而是我过去三年深度参与17个中…...
