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

ThreadLocal源码分析

文章目录

    • 1.核心数据结构 ThreadLocalMap
        • 1.静态内部类 Entry
        • 2.真正存储数据的是table数组
    • 2.ThreadLocal.set()方法源码详解
        • 1.set
        • 2.getMap
        • 3.ThreadLocalMap.set
        • 4.createMap
        • 5.rehash
        • 6.resize
    • 3.ThreadLocalMap.get()详解
        • 1.get
        • 2.ThreadLocalMap.getEntry
        • 3.getEntryAfterMiss
    • 4.ThreadLocalMap过期 key 的探测式清理流程
    • 5.InheritableThreadLocal原理

1.核心数据结构 ThreadLocalMap

1.静态内部类 Entry
// 继承了弱引用
static class Entry extends WeakReference<ThreadLocal<?>> {// value就是平常定义ThreadLocal中存的那个东西Object value;// key就是ThreadLocal(是弱引用)Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}
}
2.真正存储数据的是table数组

CleanShot 2025-02-02 at 11.57.50@2x

2.ThreadLocal.set()方法源码详解

1.set
    public void set(T value) {// 获取当前线程Thread t = Thread.currentThread();// 获取当前线程的ThreadLocalMapThreadLocalMap map = getMap(t);// 如果map不为空,就将当前的ThreadLocal作为key,ThreadLocal存的值作为value设置到map中if (map != null) {map.set(this, value);} else {// 如果map为空,就使用当前线程和ThreadLocal存的值去创建一个mapcreateMap(t, value);}}
2.getMap
    ThreadLocalMap getMap(Thread t) {// 返回当前线程的ThreadLocalMapreturn t.threadLocals;}

CleanShot 2025-02-02 at 12.10.06@2x

3.ThreadLocalMap.set
private void set(ThreadLocal<?> key, Object value) {// We don't use a fast path as with get() because it is at// least as common to use set() to create new entries as// it is to replace existing ones, in which case, a fast// path would fail more often than not.// 存储数据的Entry数组Entry[] tab = table;// 数组的长度int len = tab.length;// 计算当前的ThreadLocal对象在Entry数组中的位置,其实跟hashmap一样,都是(n - 1) & hashint i = key.threadLocalHashCode & (len-1);// 只要目标位置不为空,就进行循环for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {ThreadLocal<?> k = e.get();// 期间如果遇到key相同的,则替换valueif (k == key) {e.value = value;return;}// 如果遇到key为null的,就会执行替换过期数据的逻辑if (k == null) {replaceStaleEntry(key, value, i);return;}}// 如果目标位置为空,就直接将这个Entry对象放进去tab[i] = new Entry(key, value);int sz = ++size;// 如果清理过期槽位失败并且元素数量大于等于阈值(数组长度乘2/3)就进行rehash逻辑if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash();
}
4.createMap
void createMap(Thread t, T firstValue) {// 使用ThreadLocal对象和value去创建一个mapt.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {// table的初始容量为16table = new Entry[INITIAL_CAPACITY];// 使用(n - 1) & hash去找到指定的table数组的位置int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);// 给指定位置的table数组设置一个Entry对象table[i] = new Entry(firstKey, firstValue);// 设置数组大小为1size = 1;// 设置阈值setThreshold(INITIAL_CAPACITY);
}
private void setThreshold(int len) {// 阈值为16 * 2/3threshold = len * 2 / 3;
}
5.rehash
private void rehash() {// 进行探测式清理工作expungeStaleEntries();// 如果清理后 size >= threshold * 3/4 就进行扩容if (size >= threshold - threshold / 4)resize();
}
6.resize
private void resize() {// 旧的Entry数组Entry[] oldTab = table;// 旧的容量int oldLen = oldTab.length;// 新的长度为旧长度的两倍int newLen = oldLen * 2;// 创建一个新的Entry数组Entry[] newTab = new Entry[newLen];int count = 0;// 遍历旧的数组,将旧数组中的元素重新hash后放到新数组中,如果哈希冲突就往后放for (int j = 0; j < oldLen; ++j) {Entry e = oldTab[j];if (e != null) {ThreadLocal<?> k = e.get();if (k == null) {e.value = null; // Help the GC} else {int h = k.threadLocalHashCode & (newLen - 1);while (newTab[h] != null)h = nextIndex(h, newLen);newTab[h] = e;count++;}}}setThreshold(newLen);size = count;table = newTab;
}

3.ThreadLocalMap.get()详解

1.get
public T get() {// 获取当前线程Thread t = Thread.currentThread();// 获取当前线程的ThreadLocalMapThreadLocalMap map = getMap(t);// 只要map不为空if (map != null) {// 通过当前的ThreadLocal作为key去获取到对应的ThreadLocalMap.EntryThreadLocalMap.Entry e = map.getEntry(this);// 只要不为空就返回这个valueif (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}// 如果map为空就返回一个初始值nullreturn setInitialValue();
}
2.ThreadLocalMap.getEntry
private Entry getEntry(ThreadLocal<?> key) {// (n - 1) & hash 找到table数组的位置int i = key.threadLocalHashCode & (table.length - 1);Entry e = table[i];// 如果key相同,直接返回if (e != null && e.get() == key)return e;else// 如果key不同,就向后找,如果最后找到了就返回,找不到就返回nullreturn getEntryAfterMiss(key, i, e);
}
3.getEntryAfterMiss
        private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {Entry[] tab = table;int len = tab.length;while (e != null) {ThreadLocal<?> k = e.get();if (k == key)return e;if (k == null)expungeStaleEntry(i);elsei = nextIndex(i, len);e = tab[i];}return null;}

4.ThreadLocalMap过期 key 的探测式清理流程

遍历散列数组,从开始位置向后探测清理过期数据,将过期数据的Entry设置为null

沿途中碰到未过期的数据则将此数据rehash后重新在table数组中定位,如果定位的位置已经有了数据,则会将未过期的数据放到最靠近此位置的Entry=null的桶中,使rehash后的Entry数据距离正确的桶的位置更近一些。

5.InheritableThreadLocal原理

实现原理是子线程是通过在父线程中通过调用new Thread()方法来创建子线程,Thread#init方法在Thread的构造方法中被调用。在init方法中拷贝父线程数据到子线程中:

private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc,boolean inheritThreadLocals) {if (name == null) {throw new NullPointerException("name cannot be null");}if (inheritThreadLocals && parent.inheritableThreadLocals != null)this.inheritableThreadLocals =ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);this.stackSize = stackSize;tid = nextThreadID();
}

相关文章:

ThreadLocal源码分析

文章目录 1.核心数据结构 ThreadLocalMap1.静态内部类 Entry2.真正存储数据的是table数组 2.ThreadLocal.set()方法源码详解1.set2.getMap3.ThreadLocalMap.set4.createMap5.rehash6.resize 3.ThreadLocalMap.get()详解1.get2.ThreadLocalMap.getEntry3.getEntryAfterMiss 4.Th…...

Python爬虫实战:获取笔趣阁图书信息,并做数据分析

注意:以下内容仅供技术研究,请遵守目标网站的robots.txt规定,控制请求频率避免对目标服务器造成过大压力! 1. 环境准备与反爬策略 python import requests from bs4 import BeautifulSoup import pandas as pd import re import time import random from fake_useragent …...

如何在Java EE中使用标签库?

在Java EE&#xff08;现在称为Jakarta EE&#xff09;中使用标签库&#xff08;Tag Library&#xff09;&#xff0c;主要是通过JSP标准标签库&#xff08;JSTL&#xff09;或自定义标签库来实现的。标签库允许在JSP页面中使用自定义的标签&#xff0c;从而简化页面逻辑、增强…...

3天功能开发→3小时:通义灵码2.0+DEEPSEEK实测报告,单元测试生成准确率92%的秘密

前言 随着人工智能技术的迅猛发展&#xff0c;AI 赋能编程成为了必然趋势。通义灵码应运而生&#xff0c;它是阿里巴巴集团在人工智能与编程领域深度探索的结晶。通义灵码旨在借助 AI 的强大能力&#xff0c;为开发者提供更加智能、高效的编程辅助工具。通义灵码 2.0 作为其升…...

STM32 Flash详解教程文章

目录 Flash基本概念理解 Flash编程接口FPEC Flash擦除/写入流程图 Flash选项字节基本概念理解 Flash电子签名 函数读取地址下存放的数据 Flash的数据处理限制部分 编写不易&#xff0c;请勿搬运&#xff0c;感谢理解&#xff01;&#xff01;&#xff01; Flash基本概念…...

ubuntu服务器部署

关闭欢迎消息 服务器安装好 ubuntu 系统后&#xff0c;进行终端登录&#xff0c;会显示出很多的欢迎消息 通过在用户的根目录下执行 touch .hushlogin 命令&#xff0c;再次登录终端就不会出现欢迎消息 修改hostname显示 修改 /etc/hostname 文件内容为主机名&#xff0c;保…...

小爱音箱控制手机和电视听歌的尝试

最近买了小爱音箱pro&#xff0c;老婆让我扔了&#xff0c;吃灰多年的旧音箱。当然舍不得&#xff0c;比小爱还贵&#xff0c;刚好还有一台红米手机&#xff0c;能插音箱&#xff0c;为了让音箱更加灵活&#xff0c;买了个2元的蓝牙接收模块Type-c供电3.5接口。这就是本次尝试起…...

问卷数据分析|SPSS实操之独立样本T检验

适用条件&#xff1a; 检验分类变量和定量变量之间的差异 分类变量只能为二分类变量&#xff0c;如性别 1.选择分析--比较平均值--独立样本检验 2. 在下方选择性别&#xff08;分类变量&#xff09; 3. 点击定义组&#xff0c;组1输入1&#xff0c;组2输入2 4.在上方填入定量…...

Linux 内核 IPoIB 驱动中 sysfs 属性冲突问题的分析与解决

一、引言 在 Linux 内核的设备驱动开发中,sysfs 文件系统是一种重要的机制,用于向用户空间暴露内核对象的属性信息。通过 sysfs,用户空间程序可以读取或修改设备的属性,从而实现对硬件设备的监控和配置。然而,在实际开发中,可能会遇到 sysfs 属性冲突的问题,特别是在复…...

双ESP8266-01S通讯UDP配置

第一台ESP8266(发送命令需要勾---发送新行) ATCWMODE3 ATCWSAP_DEF"CAR_wifi_Master","12345678",5,3 //设置本地wifi名称以及密码 ATCIPSTA_DEF"192.168.4.1" //设置本地IP ATCIFSR …...

【C】初阶数据结构5 -- 栈

前面学习了两种最基本的数据结构 -- 顺序表和链表&#xff0c;接下来就可以基于这两种数据结构来实现其他数据结构了。其实&#xff0c;其他的数据结构的物理结构要么是数组&#xff0c;要么就是链表&#xff0c;所以学好顺序表和链表是学好其他数据结构的基础。接下里&#xf…...

闭源大语言模型的怎么增强:提示工程 检索增强生成 智能体

闭源大语言模型的怎么增强 提示工程 检索增强生成 智能体 核心原理 提示工程:通过设计和优化提示词,引导大语言模型进行上下文学习和分解式思考,激发模型自身的思维和推理能力,使模型更好地理解和生成文本,增强其泛用性和解决问题的能力。检索增强生成:结合检索的准确…...

C语言-------结构体(1)

数据类型 &#xff08;1&#xff09;基本数据类型 整型 浮点型 字符型 &#xff08;2&#xff09;构造类型 数组 结构体 结构体: 用来处理&#xff0c;现实生活中&#xff0c;更复杂的数据的描述 用来 描述复杂数据的 一种用户自定义的数…...

org.apache.kafka.common.errors.TimeoutException

个人博客地址&#xff1a;org.apache.kafka.common.errors.TimeoutException | 一张假钞的真实世界 使用kafka-console-producer.sh向远端Kafka写入数据时遇到以下错误&#xff1a; $ bin/kafka-console-producer.sh --broker-list 172.16.72.202:9092 --topic test This is …...

Ceph集群搭建2025(squid版)

squid版本维护年限 apt install -y cephadmecho >> "deb http://mirrors.163.com/ceph/debian-squid/ bookworm main" echo >> "deb-src http://mirrors.163.com/ceph/debian-squid/ bookworm main"#安装源 cephadm install #开始初始化一个最…...

DeepSeek从入门到精通:提示词设计的系统化指南

目录 引言&#xff1a;AIGC时代的核心竞争力 第一部分 基础篇&#xff1a;提示词的本质与核心结构 1.1 什么是提示词&#xff1f; 1.2 提示词的黄金三角结构 第二部分 类型篇&#xff1a;提示词的六大范式 2.1 提示语的本质特征 2.2 提示语的类型 2.2.1 指令型提示词 …...

python后端调用Deep Seek API

python后端调用Deep Seek API 需要依次下载 ●Ollama ●Deepseek R1 LLM模型 ●嵌入模型nomic-embed-text / bge-m3 ●AnythingLLM 参考教程&#xff1a; Deepseek R1打造本地化RAG知识库:安装部署使用详细教程 手把手教你&#xff1a;deepseek R1基于 AnythingLLM API 调用本地…...

自有证书的rancher集群使用rke部署k8s集群异常

rancher使用自签域名&#xff0c;或者商业证书容易踩到的坑。 最开始的报错&#xff1a; docker logs kubelet‘s id E0214 13:04:14.590268 9614 pod_workers.go:1300] "Error syncing pod, skipping" err"failed to \"StartContainer\" for …...

【线性代数】1行列式

1. 行列式的概念 行列式的符号表示: 行列式的计算结果:一个数 计算模型1:二阶行列式 二阶行列式: 三阶行列式: n阶行列式: 🍎计算行列式 计算模型2:上三角形行列式 上三角形行列式特征:主对角线下皆为0。 上三角形行列式: 化上三角形通用方法:主对角线下,…...

DeepSeek免费部署到WPS或Office

部署到WPS - 通过OfficeAI插件接入&#xff1a; - 准备工作&#xff1a;安装最新版本的WPS Office软件&#xff1b;访问DeepSeek官网&#xff0c;点击右上角的“API开放平台”&#xff0c;登录账号&#xff08;若无账号需先注册&#xff09;&#xff0c;登录成功后&#xff0c;…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...