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

【Java核心知识】ThreadLocal相关知识

ThreadLocal

什么是ThreadLocal

ThreadLoacal类可以为每个线程保存一份独有的变量,该变量对于每个线程都是独占的。实现原理为每个Thread类中包含一个ThreadHashMapkey为变量的对应的ThreadLocal对象value为变量的

在日常使用中,我们可以通过set(value)方法设置值,然后通过get()方法获取值,示例代码如下:

我们通过线程池执行了五个线程,每个线程都有一份自己独有的id变量,实现了线程间的数据隔离。

@Slf4j
public class ThreadLocalTest {// ThreadLocal 变量,每个线程都有自己的副本private static final ThreadLocal<Integer> id = new ThreadLocal<>();@Testpublic void testThreadLocal() {// 创建线程池ExecutorService executorService = Executors.newCachedThreadPool();try {for (int i = 0; i < 5; i ++) {int finalI = i;executorService.execute(() -> {// 设置ThreadLocal 变量    id.set(finalI);// 获取ThreadLocal变量log.info("The id of thread {} is {}", Thread.currentThread().getName(), id.get());});}} finally {id.remove();executorService.shutdown();}}
}

传统的HashMap是链地址法,发生碰撞放入桶内;ThreadLocalMap是开放地址法,发生冲突放到后一位

实现原理

那如何实现这种线程间的数据隔离呢?一种容易想到的方法是在Map中进行存储,每个ThreadLocal变量内维护一个Map,其中key为每个线程的IDvalue为对应的值。这样当调用get()方法时,会通过hash算法找到对应线程的值。

jdk也确实是这么做的,只不过存放元素Map的实现不是HashMap,而是ThreadLocalMap,解决冲突的做法是开放寻址法,即出现冲突就往下一个临近位置找,直到找到空位置。

早期的实现中,多个线程会共享一个ThreadLocalMap,这样随着线程数的增加,map就需要扩容,会消耗较多的资源;

后来,每个线程都有自己的一个ThreadLocalMap,各自保存自己的局部变量,key为变量名,value为变量值。

因为局部变量很少,所以一般不需要扩容。

内存泄漏

下面这张图是ThreadLocal对应的引用关系,可以看到,在新的设计下,ThreadLocalMap存在于Thread中,是和Thread的生命周期一致的。

在这里插入图片描述

ThreadLocalMapkeyThreadLocal对象,value是对应的值,需要注意的是ThreadHashMapkey会使用弱引用,这主要是为了当ThreadLocalnull后,除了ThreadHashMap持有的弱引用外,没有别的强引用,ThreadLocal对象可以被GC回收

但是这样就导致ThreadHashMap中对应的keynull,其value引用的对象不会被GC回收,从而出现了内存泄漏。

所以在使用完ThreadLocal变量后,尽量使用remove()方法进行清理,这样会把keynull的键值对删除。

再回到上面的示例,上面的示例我们使用final修饰了ThreadLocal,保证其不会被修改,这样做会导致ThreadLocal永远存在强引用,不会被释放,容易发生内存泄露,所以需要我们显示调用remove()方法进行清理。

参考链接

ThreadLocal的内存泄露?什么原因?如何避免?

相关文章:

【Java核心知识】ThreadLocal相关知识

ThreadLocal 什么是ThreadLocal ThreadLoacal类可以为每个线程保存一份独有的变量&#xff0c;该变量对于每个线程都是独占的。实现原理为每个Thread类中包含一个ThreadHashMap&#xff0c;key为变量的对应的ThreadLocal对象&#xff0c;value为变量的值。 在日常使用中&…...

《Python基础教程(第三版)》阅读笔记 1

目录 1 快速上手&#xff1a;基础知识2 列表和元组3 字符串4 字典5 条件、循环及其他6 抽象7 再谈抽象8 异常9 魔法方法、特性和迭代器10 开箱即用 本文参考自《Beginning Python: from novice to professional》&#xff0c;中文版为《Python基础教程&#xff08;第三版&#…...

坦克400 Hi4-T预售价28.5万元起,越野新能源好理解

8月25日&#xff0c;在以“智享蓉城&#xff0c;驭见未来”为主题的成都国际车展上&#xff0c;坦克品牌越野新能源再启新程&#xff0c;首次以全Hi4-T新能源阵容亮相展台&#xff0c;释放坦克品牌加速布局越野新能源的强烈信号。 Hi4-T架构首款落地车型坦克500 Hi4-T上市至今斩…...

我的Vim学习笔记(不定期更新)

2023年9月3日&#xff0c;周日上午 学到了啥就写啥&#xff0c;不定期更新 目录 字体 文件 标签页 分屏 调用系统命令 字体 设置字体大小 :set guifont字体:h字体大小 例如&#xff0c;:set guifontMonospace:h20 查询当前使用的字体和字体大小 :set guifont? 查看…...

spring boot项目生成容器并运行

一个安静的周末&#xff0c;shigen又睡懒觉了&#xff0c;上次说的拖延症的惩罚来了&#xff1a;早晚各100个健腹轮练习&#xff0c;早上的已经完成了。今天的文章来的有点晚&#xff0c;但是依旧保持质量。 springboot项目生成容器并运行 背景 将springboot项目打包成jar包&…...

Vue之html中特殊符号的展示

Vue之html中特殊符号的展示 在html中使用特殊字符时直接展示会报错&#xff0c;需要使用实体名称或者实体编号才能展示。 最常用的字符实体 显示结果 描述 实体名称 实体编号空格 < 小于号 < &…...

数据结构1 -- leetcode练习

三. 练习 3.1 时间复杂度 用函数 f ( n ) f(n) f(n) 表示算法效率与数据规模的关系&#xff0c;假设每次解决问题需要 1 微秒&#xff08; 1 0 − 6 10^{-6} 10−6 秒&#xff09;&#xff0c;进行估算&#xff1a; 如果 f ( n ) n 2 f(n) n^2 f(n)n2 那么 1 秒能解决多…...

Java设计模式:四、行为型模式-05:备忘录模式

文章目录 一、定义&#xff1a;备忘录模式二、模拟场景&#xff1a;备忘录模式三、改善代码&#xff1a;备忘录模式3.1 工程结构3.2 备忘录模式模型结构图3.3 备忘录模式定义3.3.1 配置信息类3.3.2 备忘录类3.3.3 记录者类3.3.4 管理员类 3.4 单元测试 四、总结&#xff1a;备忘…...

MongoDB实验——MongoDB配置用户的访问控制

MongoDB 配置用户的访问控制 一、 实验原理 理解admin数据库&#xff1a;安装MongoDB时&#xff0c;会自动创建admin数据库&#xff0c;这是一个特殊数据库&#xff0c;提供了普通数据库没有的功能&#xff0c;例如&#xff0c;有些账户角色赋予用户操作多个数据库的权限&…...

golang逃逸技术分析

“ 申请到栈内存好处&#xff1a;函数返回直接释放&#xff0c;不会引起垃圾回收&#xff0c;对性能没有影响。 申请到堆上面的内存才会引起垃圾回收。 func F() { a : make([]int, 0, 20) b : make([]int, 0, 20000) l : 20 c : make([]int, 0, l)} “ a和b代码一样&#xff0…...

说说你了解的 Nginx

分析&回答 nginx性能数据 高并发连接: 官方称单节点支持5万并发连接数&#xff0c;实际生产环境能够承受2-3万并发。内存消耗少: 在3万并发连接下&#xff0c;开启10个nginx进程仅消耗150M内存 (15M10150M) 1. 正向、反向代理 所谓“代理”&#xff0c;是指在内网边缘 …...

SpringWeb(SpringMVC)

目录 SpringWeb介绍 搭建 SpringWeb SpringWeb介绍 Spring Web是一个基于 Servlet API 构建的原始 web 框架&#xff0c;用于构建基于MVC模式的Web应用程序。在 web 层框架历经 Strust1&#xff0c;WebWork&#xff0c;Strust2 等诸多产品的历代更选 之后&#xff0c;目前业界普…...

Mysql 语句

数据库管理 SQL语言分类 DDL 数据定义语言&#xff0c;用于创建数据库对象&#xff0c;如库、表、索引等 create 创建 create database/table; 数据库/表 create table 表名 &#xff08;括号内添加类型和字段&#xff09;;drop 删除 drop database/table; 数据库/表…...

软考高级架构师——6、软件架构设计

像学写文章一样&#xff0c;在学会字、词、句之后&#xff0c;就应上升到段落&#xff0c;就应追求文章的“布局谋 篇”&#xff0c;这就是架构。通俗地讲&#xff0c;软件架构设计就是软件系统的“布局谋篇”。 人们在软件工程实践中&#xff0c;逐步认识到了软件架构的重要性…...

虚拟内存相关笔记

虚拟内存是计算机系统内存管理的一个功能&#xff0c;它允许程序认为它们有比实际物理内存更多的可用内存。它使用硬盘来模拟额外的RAM。当物理内存不足时&#xff0c;操作系统将利用磁盘空间作为虚拟内存来存储数据。这种机制提高了资源的利用率并允许更大、更复杂的应用程序的…...

【linux】定时任务讲解

文章目录 一. 在某时刻只执行一次&#xff1a;at1. 设置定时任务2. 查看和删除定时任务 二. 周期性执行任务&#xff1a;cron1. 启动crond进程2. 编辑定时任务3. 查看和删除4. 用户权限4.1. 黑名单4.2指定用户 三. /etc/crontab的管理 一. 在某时刻只执行一次&#xff1a;at 1…...

安卓10创建文件夹失败

最近在做拍照录像功能&#xff0c;已经有了文件读写权限&#xff0c;却发现在9.0手机上正常使用&#xff0c;但是在安卓12系统上根本没有创建文件夹。经过研究发现&#xff0c;创建名称为“DCIM”的文件夹可以&#xff0c;别的又都不行。而且是getExternalStorageDirectory和ge…...

文件操作(c/c++)

文件操作可以概括为几步&#xff1a; 打开文件&#xff0c;写入文件&#xff0c;读取文件&#xff0c;关闭文件 FILE FILE 是一个在C语言中用于文件操作的库函数&#xff0c;它提供了一系列函数来实现文件的创建、打开、读取、写入、关闭等操作。FILE 库函数可以帮助开发者处理…...

设计模式-适配器

文章目录 一、简介二、适配器模式基础1. 适配器模式定义与分类2. 适配器模式的作用与优势3.UML图 三、适配器模式实现方式1. 类适配器模式2. 对象适配器模式3.类适配器模式和对象适配器模式对比 四、适配器模式应用场景1. 继承与接口的适配2. 跨平台适配 五、适配器模式与其他设…...

C. Queries for the Array - 思维

分析&#xff1a; 分析出现矛盾的地方&#xff0c;也就是可能遇到0&#xff0c;并且已有字符串的长度小于等于1&#xff0c;另一种情况就是&#xff0c;遇到了1并且已有字符串不是排好序的&#xff0c;或者遇到了0已有字符串是排好序的&#xff0c;那么可以遍历字符串&#xff…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...