ThreadLocal数据结构、内存泄漏分析

文章目录

  • ⚽ThreadLocal
    • 🎉入门案例
    • 🎈ThreadLocal在线程中怎么存储的
    • 🎗为什么会造成内存泄漏?
    • 🎃ThreadLocalMap的key使用强引用和弱引用有什么区别呢?
    • 🔔补充说明
      • Java中引用类型分类
      • 内存泄漏和内存溢出区别

⚽ThreadLocal

用来为每个线程提供独立的变量副本的

🎉入门案例

使用案例

public class ThreadLocalMultipleExample {private static final ThreadLocal<Integer> threadLocal1 = ThreadLocal.withInitial(() -> 1);private static final ThreadLocal<String> threadLocal2 = ThreadLocal.withInitial(() -> "Hello");public static void main(String[] args) {// 线程A设置值Thread threadA = new Thread(() -> {threadLocal1.set(10);threadLocal2.set("Thread A");System.out.println("Thread A - local1: " + threadLocal1.get()); // 10System.out.println("Thread A - local2: " + threadLocal2.get()); // Thread A});// 线程B设置值Thread threadB = new Thread(() -> {System.out.println("Thread B - local1: " + threadLocal1.get()); // 1System.out.println("Thread B - local2: " + threadLocal2.get()); // Hello});threadA.start();threadB.start();}
}

运行结果:可以看到虽然线程A修改了变量的值,但是在线程B中变量的值还是初始给的值,因为这两个变量在每个线程中都有自己的副本

Thread A - local1: 10
Thread A - local2: Thread A
Thread B - local1: 1
Thread B - local2: Hello

🎈ThreadLocal在线程中怎么存储的

先来了解ThreadLocal在Thread时怎么存储的。

我们先看Thread的源码,里面有个ThreadLocalMap类型的变量。

public class Thread implements Runnable {ThreadLocal.ThreadLocalMap threadLocals = null;
}

从下面ThreadLocal的部分源码中可以看出,这个ThreadLocalMap类是ThreadLocal类中静态内部类。我们可以把ThreadLocalMap当做一个Map,其中ThreadLocalkey,存储的值就是value

可以看到ThreadLocalset、get方法,都是用Thread.currentThread()获取当前线程后,拿到每个线程自己独有的ThreadLocalMap之后进行读写操作,所以这里保证了每个线程都有自己的ThreadLocal副本。

public class ThreadLocal<T> {// ......省略部分代码static class ThreadLocalMap {static class Entry extends WeakReference<ThreadLocal<?>> {Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}}}// ......省略部分代码public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue();}// ......省略部分代码public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {map.set(this, value);} else {createMap(t, value);}}
}

ThreadLocalMapHashMap在存储结构上有些不同,HashMap是数组+链表(+红黑树)的形式,但是ThreadLocalMap是纯数组的形式,内部只有一个Entry[] table数组,其中一个Entry就是一个键值对。

使用ThreadLocal时需要注意避免出现内存泄漏问题。

🎗为什么会造成内存泄漏?

我们从源码中可以看出ThreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal不存在外部强引用时,Key(ThreadLocal)势必会被GC回收,这样就会导致ThreadLocalMap中key为null, 而value还存在着强引用,只有当thead线程退出以后,value的强引用链条才会断掉。意味着这个线程一直不结束的话,这个value就一直无法回收,造成内存泄漏,这种情况一般发生在使用线程池的场景中,因为里面的线程正常情况下会一直存活。

在平时使用ThreadLocal类时,要避免内存泄漏问题,可以在线程处理完任务后,使用threadLocal.remove()方法,移除当前threadLocal

🎃ThreadLocalMap的key使用强引用和弱引用有什么区别呢?

  • key 使用强引用:当ThreadLocalMap的key为强引用,发生GC时,因为ThreadLocalMap还持有ThreadLocal的强引用,同时ThreadLocalMap和Thread生命周期相同,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏。
  • key 使用弱引用:当ThreadLocalMap的key为弱引用,发生GC时,由于ThreadLocalMap持有的是ThreadLocal的弱引用,即使没有手动删除,ThreadLocal也会被回收。当key为null,在下一次其他ThreadLocal调用他们的set(),get(),remove()方法的时候都会清除key为null对应的value值。

🔔补充说明

Java中引用类型分类

  • 强引用:我们常常 new 出来的对象就是强引用类型,只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足的时候
  • 软引用:使用 SoftReference 修饰的对象被称为软引用,软引用指向的对象在内存要溢出的时候被回收
  • 弱引用:使用 WeakReference 修饰的对象被称为弱引用,只要发生垃圾回收,若这个对象只被弱引用指向,那么就会被回收
  • 虚引用:虚引用是最弱的引用,在 Java 中使用 PhantomReference 进行定义。虚引用中唯一的作用就是用队列接收对象即将死亡的通知

内存泄漏和内存溢出区别

  • 内存泄漏 是因为程序没有释放不再使用的内存,导致内存逐渐积累,最终可能引起内存溢出。
  • 内存溢出 是当程序请求的内存超出了系统可分配的最大值时,操作系统无法满足内存请求,从而导致程序崩溃。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/889910.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vs code 2024编译环境问题记录

之前vs code环境配置了好一会&#xff0c;现在将遇到的问题记录一下&#xff0c;并贴上解决方法。 在这之前&#xff0c;关键的gcc编译器竟然在Python生成exe的过程中不小心下载了Mingw64&#xff0c;然后导致gcc编译器已经安装好在某个目录下了 命令行查看发现&#xff0c;原…

linux网络编程 | c | epoll实现IO多路转接服务器

epoll实现IO多路转接服务器 可通过以下视频学习 06-opell函数实现的多路IO转接_哔哩哔哩_bilibili 通过响应式–多路IO转接实现 文章目录 epoll实现IO多路转接服务器1.思路&功能核心思路 2.代码实现multi_epoll_sever.c运行图 1.思路&功能 **功能&#xff1a;**客…

植物大战僵尸辅助【控制台版本】

前面介绍了使用CE和OD的简单使用&#xff1a;CE和OD介绍和使用CE查找阳光的教学&#xff1a;阳光基地址和偏移地址&#xff0c;下面先使用最简单的控制台程序来实现修改阳光的功能。 项目地址 1.分析程序 我们的控制台程序想要修改植物大战僵尸游戏内的数据&#xff0c;它们…

elasticsearch 使用Painless脚本

文章目录 1. 创建索引2. 插入模拟数据Painless 脚本的基本特点&#xff1a;Painless 脚本的常见用途1. 脚本查询和过滤示例&#xff1a;基于脚本的查询 2. 脚本字段示例&#xff1a;脚本字段 3. 聚合中的脚本示例&#xff1a;脚本聚合 4. 文档更新中的脚本示例&#xff1a;文档…

【Elasticsearch】高亮搜索:从原理到Web呈现

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

15.初始接口1.0 C#

这是一个用于实验接口的代码 适合初认识接口的人 【CSDN开头介绍】&#xff08;文心一言AI生成&#xff09; 在C#编程世界中&#xff0c;接口&#xff08;Interface&#xff09;扮演着至关重要的角色&#xff0c;它定义了一组方法&#xff0c;但不提供这些方法的实现。接口作为…

Day9 神经网络的偏导数基础

多变量函数与神经网络 在神经网络中&#xff0c;我们经常遇到多变量函数。这些函数通常描述了网络的输入、权重、偏置与输出之间的关系。例如&#xff0c;一个简单的神经元输出可以表示为&#xff1a; z f ( w 1 x 1 w 2 x 2 … w n x n b ) z f(w_1x_1 w_2x_2 \ldots…

map和set题目练习

一、习题一&#xff1a;随机链表的复制 1.1题目详情 1.2思路 在没有学习map和set之前&#xff0c;解决这道题最大的问题就在于无法建立原链表与拷贝链表的映射关系&#xff0c;只能通过在原链表每个节点后面新建一个新的链表来进行节点间的对应&#xff0c;而学习了map之后&a…

C语言入门(一):A + B _ 基础输入输出

前言 本专栏记录C语言入门100例&#xff0c;这是第&#xff08;一&#xff09;例。 目录 一、【例题1】 1、题目描述 2、代码详解 二、【例题2】 1、题目描述 2、代码详解 三、【例题3】 1、题目描述 2、代码详解 四、【例题4】 1、题目描述 2、代码详解 一、【例…

渗透测试学习笔记(五)网络

一.IP地址 1. IP地址详解 ip地址是唯一标识&#xff0c;一段网络编码局域网&#xff08;内网&#xff09;&#xff1a;交换机-网线-pcx.x.x.x 32位置2进制&#xff08;0-255&#xff09; IP地址五大类 IP类型IP范围A类0.0.0.0 到 127.255.255.255B类128.0.0.0 到191.255.25…

《自制编译器》--青木峰郎 -读书笔记 编译hello

在该书刚开始编译hello.cb时就遇到了问题。 本人用的是wsl&#xff0c;环境如下&#xff0c; 由于是64位&#xff0c;因此根据书中的提示&#xff0c;从git上下载了64位的cb编译器 cbc-64bit 问题一: 通过如下命令编译时,总是报错。 cbc -Wa,"--32" -Wl,"-…

jedis使用及注意事项

Jedis Jedis 是一个 Java 客户端&#xff0c;用于与 Redis 数据库进行交互。它提供了一系列简单易用的 API&#xff0c;使得在 Java 应用程序中使用 Redis 变得非常方便。以下是 Jedis 的使用方法及一些注意事项。 Jedis的优势 Lettuce客户端及Jedis客户端比较如下&#xff1a;…

浏览器执行机制

主线程 任务1&#xff0c;任务2 微队列微队列任务1&#xff0c; 微队列任务2延时队列延时队列任务1&#xff0c; 延时队列任务2交互队列.... 事件循环的工作原理 主线程执行同步任务&#xff1a; 主线程首先执行所有同步任务&#xff08;即栈中的任务&#xff09;。这些任务会…

Java 基础知识——part 4

8.成员方法&#xff1a;Java中必须通过方法才能对类和对象的属性操作&#xff1b;成员方法只在类的内部声明并加以实现。一般声明成员变量后再声明方法。 9.方法定义 方法的返回值是向外界输出的信息&#xff0c;方法类型和返回值类型同&#xff1b;返回值通过return返回&…

C/S软件授权注册系统(Winform+WebApi+.NET8+EFCore版)

适用软件&#xff1a;C/S系统、Winform桌面应用软件。 运行平台&#xff1a;Windows .NETCore&#xff0c;.NET8 开发工具&#xff1a;Visual Studio 2022&#xff0c;C#语言 数据库&#xff1a;Microsoft SQLServer 2012&#xff0c;Oracle 21c&#xff0c;MySQL8&#xf…

监控易 IDC 数据中心一体化智能运维平台:新质生产力的典范

一、引言 在当今数字化飞速发展的时代&#xff0c;IDC 数据中心作为信息产业的核心基础设施&#xff0c;其稳定、高效运行对于企业和社会的重要性不言而喻。随着数据量的爆炸式增长和业务复杂度的提升&#xff0c;传统的运维模式已难以满足需求&#xff0c;数据中心面临着诸多挑…

busybox学习——简单介绍

文章目录 简介官网源码目录结构构建 简介 BusyBox 将许多具有共性的小版本的UNIX工具结合到一个单一的可执行文件。这样的集合可以替代大部分常用工具比如的GNU fileutils &#xff0c; shellutils等工具&#xff0c;BusyBox提供了一个比较完善的环境&#xff0c;可以适用于任…

CTFHUB 信息泄露 备份文件下载-网站源码

根据提示应是猜测网站源码的备份文件&#xff0c;可以采用bp拼接文件名和后缀 开启bp抓包后设置第一个攻击点导入文件名 第二个攻击点导入后缀 开始暴力破解&#xff0c;有成功响应的 拼接到网站后缀后可以直接下载 解压缩后记事本的名字就是flag 总结&#xff1a; …

Latex 转换为 Word(使用GrindEQ )(英文转中文,毕业论文)

效果预览 第一步&#xff1a; 告诉chatgpt&#xff1a; 将latex格式中的英文翻译为中文&#xff08;符号和公式不要动&#xff09;,给出latex格式第二步&#xff1a; Latex 转换为 Word&#xff08;使用GrindEQ &#xff09; 视频 https://www.bilibili.com/video/BV1f242…

X射线衍射全岩分析在岩石学研究中的重要性

X射线衍射全岩分析在岩石学研究中的重要性 X射线衍射&#xff08;XRD&#xff09;全岩分析在岩石学研究中扮演着至关重要的角色&#xff0c;它是一种非破坏性的分析技术&#xff0c;能够提供岩石和矿物的精细结构信息。通过解析材料内部原子排列的特征&#xff0c;XRD不仅揭示了…