Netty源码解析---FastThreadLocal-addToVariablesToRemove方法详解

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

FastThreadLocal addToVariablesToRemove 方法详解

一、先理解要解决的问题

问题场景

假设你在一个线程中使用了多个 FastThreadLocal:

// 在某个线程中
FastThreadLocal<String> name = new FastThreadLocal<>();
name.set("张三");

FastThreadLocal<Integer> age = new FastThreadLocal<>();
age.set(25);

FastThreadLocal<String> city = new FastThreadLocal<>();
city.set("北京");

现在问题来了:当这个线程要结束或被复用时,怎么知道要清理哪些 FastThreadLocal?

你可能会说:我知道啊,清理 name、age、city 这三个就行了。

但是,在实际代码中,Netty 的框架代码并不知道你创建了哪些 FastThreadLocal!它需要一个机制来自动记录这个线程用过哪些 FastThreadLocal。

解决方案

addToVariablesToRemove 方法就是用来记录的:每当你在某个线程中使用一个 FastThreadLocal,就把它记录下来,方便以后统一清理。

二、用生活例子理解

想象你去图书馆借书:

  1. 借书时:图书管理员会在你的借书卡上记录你借了哪些书
  2. 还书时:管理员看着借书卡,知道你要还哪些书

addToVariablesToRemove 就是"在借书卡上记录"这个动作。

三、数据存储在哪里?

每个线程都有一个 InternalThreadLocalMap,里面有一个数组 indexedVariables:

线程的 indexedVariables 数组:
┌─────────────────────────────────────┐
│ [0] → 一个 Set 集合(借书卡)        │  ← 专门用来记录用过哪些 FastThreadLocal
│ [1] → name 的值 "张三"               │  ← 第一个 FastThreadLocal 的数据
│ [2] → age 的值 25                    │  ← 第二个 FastThreadLocal 的数据
│ [3] → city 的值 "北京"               │  ← 第三个 FastThreadLocal 的数据
└─────────────────────────────────────┘

关键点:

  • 数组的 [0] 位置不存数据,而是存一个 Set 集合
  • 这个 Set 集合里装的是:这个线程用过的所有 FastThreadLocal 对象本身(不是值)

四、逐行解释代码

完整代码

private static void addToVariablesToRemove(
    InternalThreadLocalMap threadLocalMap,  // 当前线程的 Map
    FastThreadLocal<?> variable) {          // 要记录的 FastThreadLocal 对象
    
    // 第 1 步:从数组的 [0] 位置取出 Set 集合
    Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
    
    Set<FastThreadLocal<?>> variablesToRemove;
    
    // 第 2 步:判断 Set 集合是否已经创建
    if (v == InternalThreadLocalMap.UNSET || v == null) {
        // 情况 1:第一次使用,还没有 Set,需要创建一个
        variablesToRemove = Collections.newSetFromMap(
            new IdentityHashMap<FastThreadLocal<?>, Boolean>()
        );
        // 把新创建的 Set 放到数组的 [0] 位置
        threadLocalMap.setIndexedVariable(variablesToRemoveIndex, variablesToRemove);
    } else {
        // 情况 2:已经有 Set 了,直接用
        variablesToRemove = (Set<FastThreadLocal<?>>) v;
    }
    
    // 第 3 步:把当前的 FastThreadLocal 对象加入 Set
    variablesToRemove.add(variable);
}

第 1 步详解

Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);

白话翻译: 去数组的 [0] 位置看看,有没有那个"借书卡"(Set 集合)。

  • variablesToRemoveIndex 的值永远是 0
  • 这一步就是取 indexedVariables[0]

第 2 步详解

if (v == InternalThreadLocalMap.UNSET || v == null) {
    // 创建新的 Set
    variablesToRemove = Collections.newSetFromMap(
        new IdentityHashMap<FastThreadLocal<?>, Boolean>()
    );
    threadLocalMap.setIndexedVariable(variablesToRemoveIndex, variablesToRemove);
} else {
    // 使用已有的 Set
    variablesToRemove = (Set<FastThreadLocal<?>>) v;
}

白话翻译:

  • 如果 [0] 位置是空的(UNSET 或 null),说明这是第一次使用,需要创建一个新的"借书卡"(Set)
  • 如果 [0] 位置已经有东西了,说明之前已经创建过"借书卡"了,直接拿来用

为什么用 IdentityHashMap?

  • 普通的 HashMap 用 equals() 判断两个对象是否相同
  • IdentityHashMap 用 == 判断,也就是判断是不是同一个对象(内存地址相同)
  • 这里我们要记录的是 FastThreadLocal 对象本身,不是它的值

第 3 步详解

variablesToRemove.add(variable);

白话翻译: 把当前这个 FastThreadLocal 对象记录到"借书卡"上。

五、完整执行流程示例

代码示例

// 假设在线程 A 中执行以下代码

// 1. 创建第一个 FastThreadLocal
FastThreadLocal<String> name = new FastThreadLocal<>();
name.set("张三");  // 这里会调用 addToVariablesToRemove

执行过程:

调用 name.set("张三")
  ↓
触发 addToVariablesToRemove(threadLocalMap, name)
  ↓
第 1 步:v = threadLocalMap.indexedVariable(0)  // 取 [0] 位置
        结果:v = UNSET(因为是第一次)
  ↓
第 2 步:v == UNSET,所以创建新的 Set
        variablesToRemove = 新的 Set{}
        把 Set 放到 [0] 位置
  ↓
第 3 步:variablesToRemove.add(name)
        现在 Set = {name}

此时数组状态:

indexedVariables[0] = Set{name}
indexedVariables[1] = "张三"

继续添加第二个

// 2. 创建第二个 FastThreadLocal
FastThreadLocal<Integer> age = new FastThreadLocal<>();
age.set(25);  // 这里会再次调用 addToVariablesToRemove

执行过程:

调用 age.set(25)
  ↓
触发 addToVariablesToRemove(threadLocalMap, age)
  ↓
第 1 步:v = threadLocalMap.indexedVariable(0)
        结果:v = Set{name}(已经有了)
  ↓
第 2 步:v != UNSET,直接用已有的 Set
        variablesToRemove = Set{name}
  ↓
第 3 步:variablesToRemove.add(age)
        现在 Set = {name, age}

此时数组状态:

indexedVariables[0] = Set{name, age}
indexedVariables[1] = "张三"
indexedVariables[2] = 25

六、这个方法的作用是什么?

作用:记录"借书卡"

每次你在线程中使用一个 FastThreadLocal,这个方法就把它记录到 indexedVariables[0] 这个 Set 里。

为什么要记录?

因为后面有个 removeAll() 方法需要清理:

public static void removeAll() {
    InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
    
    // 第 1 步:从 [0] 位置取出 Set(借书卡)
    Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
    Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
    
    // 第 2 步:遍历 Set,清理每一个 FastThreadLocal
    for (FastThreadLocal<?> ftl : variablesToRemove) {
        ftl.remove(threadLocalMap);  // 清理这个 FastThreadLocal 的数据
    }
}

白话翻译:

  1. 看看"借书卡"(indexedVariables[0])上记录了哪些 FastThreadLocal
  2. 把这些 FastThreadLocal 的数据一个个清理掉

七、总结

一句话总结

addToVariablesToRemove 方法就是:在数组的 [0] 位置维护一个 Set,记录当前线程用过哪些 FastThreadLocal 对象,方便以后统一清理。

类比理解

概念类比
indexedVariables[0]借书卡
Set<FastThreadLocal<?>>借书卡上的书籍列表
addToVariablesToRemove在借书卡上记录借了哪本书
removeAll()看着借书卡还书
FastThreadLocal 对象书本身(不是书的内容)
FastThreadLocal 的值书的内容

为什么需要这个机制?

在线程池环境中,线程会被复用。如果不清理旧数据:

  • 会导致内存泄漏
  • 下一个任务可能读到上一个任务的脏数据

通过这个"借书卡"机制,Netty 可以在任务结束时调用 removeAll(),一次性清理干净。

八、什么时候会调用这个方法?

时机 1:第一次调用 get() 方法

FastThreadLocal<String> name = new FastThreadLocal<>();
String value = name.get();  // 第一次 get,会触发 initialize()

内部流程:

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 = initialValue();  // 获取初始值
    threadLocalMap.setIndexedVariable(index, v);  // 存储值
    addToVariablesToRemove(threadLocalMap, this);  // ← 在这里记录
    return v;
}

时机 2:第一次调用 set() 方法

FastThreadLocal<String> name = new FastThreadLocal<>();
name.set("张三");  // 第一次 set

内部流程:

public final void set(V value) {
    InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
    setKnownNotUnset(threadLocalMap, value);
}

private void setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
    if (threadLocalMap.setIndexedVariable(index, value)) {
        // 返回 true 表示之前是 UNSET(第一次设置)
        addToVariablesToRemove(threadLocalMap, this);  // ← 在这里记录
    }
}

注意: 只有第一次 set 才会调用 addToVariablesToRemove,后续的 set 不会重复调用。

九、图解完整流程

初始状态

线程 A 刚创建,还没使用任何 FastThreadLocal

indexedVariables 数组:
[0] → UNSET
[1] → UNSET
[2] → UNSET
...

第一步:创建并使用第一个 FastThreadLocal

FastThreadLocal<String> name = new FastThreadLocal<>();  // index = 1
name.set("张三");

执行 addToVariablesToRemove(threadLocalMap, name):

1. 取 indexedVariables[0],发现是 UNSET
2. 创建新的 Set{}
3. 把 Set 放到 indexedVariables[0]
4. Set.add(name)

结果:
[0] → Set{name}
[1] → "张三"
[2] → UNSET
...

第二步:创建并使用第二个 FastThreadLocal

FastThreadLocal<Integer> age = new FastThreadLocal<>();  // index = 2
age.set(25);

执行 addToVariablesToRemove(threadLocalMap, age):

1. 取 indexedVariables[0],发现已经有 Set{name}
2. 直接用这个 Set
3. Set.add(age)

结果:
[0] → Set{name, age}
[1] → "张三"
[2] → 25
[3] → UNSET
...

第三步:清理所有 FastThreadLocal

FastThreadLocal.removeAll();

执行流程:

1. 取 indexedVariables[0],得到 Set{name, age}
2. 遍历 Set:
   - 调用 name.remove(),清理 indexedVariables[1]
   - 调用 age.remove(),清理 indexedVariables[2]

结果:
[0] → UNSET
[1] → UNSET
[2] → UNSET
...

十、常见疑问解答

Q1:为什么要用 Set,不用 List?

A:因为 Set 可以自动去重。如果你多次调用 set(),不会重复添加同一个 FastThreadLocal。

Q2:为什么用 IdentityHashMap 而不是普通 HashMap?

A:

  • 普通 HashMap:用 equals() 判断相等,需要计算 hashCode
  • IdentityHashMap:用 == 判断相等(比较内存地址),更快

我们要记录的是 FastThreadLocal 对象本身,不关心它的内容,所以用 == 就够了。

Q3:variablesToRemoveIndex 为什么是 0?

A:因为 FastThreadLocal 类加载时,第一个调用 nextVariableIndex(),所以得到 0。

public class FastThreadLocal<V> {
    // 类加载时执行,得到 index = 0
    private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();
}

Q4:如果我从不调用 removeAll(),会怎样?

A:

  • 在普通线程中:线程结束时,整个 InternalThreadLocalMap 会被 GC 回收,没问题
  • 在线程池中:线程会被复用,旧数据不会被清理,导致内存泄漏和数据污染

所以 Netty 的 EventLoop 线程在每次任务结束后都会调用 removeAll()。

SQL Server2008详细安装步骤(超详细步骤) https://pan.baidu.com/s/1yvolqfU-AbiuGrIzblA7pA 提取码:lzw81.下载好安装包后解压到除C盘以外的磁盘,避免系统卡顿2.使用管理员身份打开安装程序注意:使用管理员身份打开时,此时如果显示以下画面属于正常现象,下载安装即可。因为.net现在有很多软件都需要,包括SQLSERVER2008,它里面有visual studio都要有net,电脑系统没有的话安装一下好了。3.选择全新安装或向现有安装添加新功能4.点击确定5.出现以下画面之后,输入产品密钥即可(密钥在 阅读详情

相关推荐

使用Docker搭建SearXNG搜索引擎

【代码】使用Docker搭建SearXNG搜索引擎。

janthinasnail的博客 1173

深入理解 Netty FastThreadLocal

ThreadLocal是JDK提供的一个方便对象在本线程内不同方法中传递、获取的类。用它定义的变量,仅在本线程中可见,不受其他线程的影响,与其他线程相互隔离。那具体是如何实现的呢?如图1所示,每个线程都会有个ThreadLocalMap实例变量,其采用懒加载的方式进行创建,当线程第一次访问此变量时才会去创建。ThreadLocalMap使用线性探测法存储ThreadLocal对象及其维护的数据,具体操作逻辑如下:假设有一个新的ThreadLocal对象,通过hash计算它应存储的位置下标为x。

ZL4120505的博客 962

二、租用AutoDL服务器与连接教程

点击右上角控制台,选择【租用新的实例】;,我这里使用的是xshell和xftp工具(自行下载)。打开本地目录和服务器目录,直接拖动文件。

zzf021122的博客 1329

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

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

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

c++通过自然语言处理技术分析语音信号音高

其中,缓冲区大小为2048,最小基频为80Hz,最大基频为1000Hz。通常情况下,音高在85Hz到255Hz之间,因此可以根据实际情况修改最小和最大基频值。C++中可以使用数字信号处理库或语音处理库,比如MATLAB、Praat、YIN算法等等来进行音高分析。对于语音信号的音高分析,可以使用基频提取技术。基频是指一个声音周期的重复率,也就是一个声音波形中最长的周期。通常情况下,人的声音基频范围是85Hz到255Hz。这段代码使用了YIN算法来计算语音信号的基频,得出的结果即为音高。

SYC20110120的博客 1729

Hcaptcha验证码的‘免浏览器’破解思路:协议分析与N值算法逆向

本文深入解析Hcaptcha验证码的‘免浏览器’破解思路,通过协议分析与N值算法逆向,实现高效自动识别。文章详细拆解Hcaptcha的API交互流程,揭示关键参数`req`和`n`的生成机制,并提供轻量级实现方案,显著降低资源消耗,适用于大规模数据采集等场景。

weixin_30838873的博客 536

Netty中FastThreadLocal源码分析

Netty中使用FastThreadLocal替代JDK中的ThreadLocal 【JAVA】ThreadLocal源码分析,其用法和ThreadLocal 一样,只不过从名字FastThreadLocal来看,其处理效率要比JDK中的ThreadLocal要高 在类加载的时候,先初始化了一个静态成员: private static final int variablesToRemoveInde...

Z_ChenChen的博客 461

[软考]系统架构设计师 备考经验分享(一) - 备考计划篇

前言 上周末刚刚结束了软考架构师的考试,自我感觉考的还可以,大概率是过了。 两次参加软考,一次中级嵌入式,一次高级架构师,都是备考不到两个月时间,尤其是架构师这次考试内容和本职工作有不小的差别,并且需要同时备考三个科目,在高强度地备考中感觉是摸索出到了一点软考的技巧与经验。 打算趁还记得,赶紧写几篇文章做下梳理总结,算是给将来自己考系分、高项或者其他考试做个记录,也希望能够帮到正在备考的大家。 先把第一步,个人的备考计划分享给大家。 自身情况分析 首先,请大家一定先明确三个问题,这三个问题会直接影响到你的

_ 6405

Netty高性能组件——FastThreadLocal源码解析(细微处见真章)

文章目录1. 前言2. ThreadLocalMap3. FastThreadLocalThread4. FastThreadLocal4.1 InternalThreadLocalMap4.2 FastThreadLocal初始化4.3 FastThreadLocal变量获取及删除总结 原博文,点击这里 1. 前言 netty自行封装了FastThreadLocal以替换jdk提供的ThreadLocal,结合封装的FastThreadLocalThread,在多线程环境下的变量提高了ThreadLoca

weixin_42030357的博客 440

让 ABAP 内表真正释放内存:从 CLEAR、FREE 到打破 Table Sharing 的实战技巧

ABAP内表内存管理的关键在于理解其运行时结构:DELETE操作仅逻辑删除行而不会释放内存,CLEAR或FREE才能真正回收内存。常见的误区包括误判空表状态和忽视内表共享机制。实际应用中,大表筛选后应采用VALUE表达式或逐行插入方式重建表体以释放内存。典型案例显示,正确处理内表内存可显著降低SAP Gateway和批处理程序的内存消耗,提升系统稳定性。开发时需结合调试工具观察内存状态,避免因共享机制导致无效回收。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 325

得物(毒)App潮鞋价格波动监控系统实战:从爬虫开发到数据可视化完整指南

本文将带领您从零开始构建一套完整的得物潮鞋价格监控系统,涵盖爬虫开发、数据存储、价格波动分析和可视化展示等全流程技术。我们将使用最新的Python技术栈,包括异步爬虫框架、智能代理池、反爬虫绕过技巧,以及基于机器学习的时间序列预测模型。无论您是想要追踪特定鞋款价格的潮流爱好者,还是希望构建商业级监控系统的开发者,这篇文章都将为您提供切实可行的解决方案。

2201_76125261的博客 2506

Netty源码分析-FastThreadLocal

FastThreadLocal源码分析 public class FastThreadLocal<V> { //这个值是FastThreadLocal的静态变量,所有的FastThreadLocal都用这个值,它是唯一的。 //在InternalThreadLocalMap有一个Object类型的数组indexedVariables //那么indexedVariable...

大新博客 843

安卓手机老版本微信无法登录?无需root 一招教你如何搞定!旧版本照样登录,微信7.0亲测有效

微信我试了清缓存、用不同的版本、甚至关网登录都不行。于是我研究了一下背后的原理,发现这不仅是个技巧,还是微信设计的一点“疏忽”——**只要有方法,旧版本照样能用**。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 1万+

netty源码阅读之性能优化工具类之FastThreadLocal的set方法实现

FastThreadLocal的set方法实现我们从以下三点分析: 1、获取ThreadLocalMap 2、直接通过索引set对象 3、如果需要remove对象,那就remove 我们还是从set方法源码开始: /** * Set the value for the current thread. */ public final void set(...

翻身咸鱼的博客 387

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

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

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

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

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

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

zi_wu_xian的专栏 327

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

第三篇 第 6 课

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

weixin_41618057的博客 516

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

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

qq_38468358的博客 351

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

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

nice_lcj520的博客 541

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

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

蒙眼过河 420

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时代写出感动人心的好文章 162
上一篇: Netty源码分析----FastThreadLocal-index生成机制详解
不早睡不改名@
博客等级 码龄5年 536粉丝 306原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值