【线程本地变量ThreadLocal】—— 每天一点小知识

news2024/11/17 11:42:32

在这里插入图片描述

                                                                              💧 线程本地变量 T h r e a d L o c a l \color{#FF1493}{线程本地变量ThreadLocal} 线程本地变量ThreadLocal💧          


🌷 仰望天空,妳我亦是行人.✨
🦄 个人主页——微风撞见云的博客🎐
🐳 《数据结构与算法》专栏的文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺
💧 《Java学习笔记》专栏的文章是本人在Java学习中总结的一些知识点~ 💐
🥣 《每天一点小知识》专栏的文章可以丰富你的知识库,滴水成河~ 🌊
🎐 《Redis》专栏的文章是在学习Redis时,整理的笔记与记录的思考~ 🥏
🥕 《RabbitMQ》专栏的文章是在学习尚硅谷课程时整理的笔记,方便复习巩固~ 🍑
🪁 希望本文能够给读者带来一定的帮助~🌸文章粗浅,敬请批评指正!🐥


文章目录

  • 🐳线程本地变量 ThreadLocal
    • 一、ThreadLocal的概念
    • 二、ThreadLocal的使用场景
    • 三、ThreadLocal的具体用法
      • 1. 创建ThreadLocal变量
      • 2. 设置和获取ThreadLocal变量的值
      • 3. 使用ThreadLocal作为方法局部变量
    • 四、ThreadLocal其他知识点补充
      • 1. ThreadLocal的原理和特点
      • 2. ThreadLocal与NIO的关系
      • 3. ThreadLocal的key
    • 五、使用ThreadLocal时的注意事项
  • 🐳结语


🐳线程本地变量 ThreadLocal

ThreadLocal是Java中的一个重要概念,它为我们提供了一种在多线程环境下安全地共享数据的方式。在本篇文章中,我们将深入探讨ThreadLocal是什么、使用场景、具体用法以及其他相关知识点,从而帮助我们更好地理解和应用ThreadLocal。

在这里插入图片描述


一、ThreadLocal的概念

  💧ThreadLocal是Java中的一个类,它用于创建线程局部变量。线程局部变量是每个线程都有自己独立的一个变量副本,而这个副本对其他线程是不可见的。这意味着每个线程都可以修改自己的变量副本,而不会影响其他线程的变量副本。这种方式使得多线程下的数据共享变得相对安全。

  💧每一个 Thread 对象均含有一个 ThreadLocalMap 类型的成员变量 ThreadLocals,它存储本线程中所有ThreadLocal对象及其对应的值

  💧ThreadLocalMap 由一个个 Entry 对象构成。Entry 继承自 WeakReference<ThreadLocal<?>>一个 Entry 由 ThreadLocal 对象和 Object 构成(Object就是我们要存的值)。由此可见, Entry 的key是ThreadLocal对象,并且是一个弱引用。当没指向key的强引用后,该key就会被垃圾收集器回收。

  💧当执行set方法时,ThreadLocal首先会获取当前线程对象,然后获取当前线程的ThreadLocalMap对象。再以当前ThreadLocal对象为key,将值存储进ThreadLocalMap对象中。

  💧get方法执行过程类似。ThreadLocal首先会获取当前线程对象,然后获取当前线程的ThreadLocalMap对象。再以当前ThreadLocal对象为key,获取对应的value。

  💧由于每一条线程均含有各自私有的ThreadLocalMap容器,这些容器相互独立互不影响,因此不会存在线程安全性问题,从而也无需使用同步机制来保证多条线程访问容器的互斥性


二、ThreadLocal的使用场景

  💧ThreadLocal的主要使用场景总体包括以下几个方面:

  1. 线程数据共享在多线程环境下,如果多个线程需要共享一些数据,而又要避免数据竞争和不一致性问题,可以使用ThreadLocal来实现线程间的数据共享
  2. 线程安全性ThreadLocal变量在每个线程中都是独立的,因此可以用来保证线程安全性。例如,在Web应用中,可以使用ThreadLocal来存储当前线程的用户会话信息,以确保多个请求之间的用户会话信息隔离。
  3. 性能优化由于ThreadLocal变量在每个线程中都有自己的副本,因此可以避免线程之间共享数据带来的额外开销,从而提高程序的性能。

💧使用ThreadLocal来解决 数据库连接

private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {
		public Connection initialValue() {
   			return DriverManager.getConnection(DB_URL);
	}
};
 
public static Connection getConnection() {
	return connectionHolder.get();
}

💧使用ThreadLocal来解决 Session管理

private static final ThreadLocal threadSession = new ThreadLocal();
 
public static Session getSession() throws InfrastructureException {
    Session s = (Session) threadSession.get();
    try {
        if (s == null) {
            s = getSessionFactory().openSession();
            threadSession.set(s);
        }
    } catch (HibernateException ex) {
        throw new InfrastructureException(ex);
    }
    return s;
}

三、ThreadLocal的具体用法

1. 创建ThreadLocal变量

  💧首先,我们需要创建一个ThreadLocal变量。例如:

public static final ThreadLocal<Integer> LOCAL_变量名 = new ThreadLocal<>();

2. 设置和获取ThreadLocal变量的值

  💧我们可以使用set方法来为每个线程设置一个独立的变量副本,如下所示:

LOCAL_变量名.set();

  💧我们可以通过get方法来获取当前线程的ThreadLocal变量值:

Object value = LOCAL_变量名.get();

3. 使用ThreadLocal作为方法局部变量

  💧我们可以在方法中使用ThreadLocal作为局部变量,这样每个线程都会有一个独立的ThreadLocal变量副本。例如:

public void someMethod() {
    LOCAL_变量名.set();
    // ... some code ...
    Object value = LOCAL_变量名.get();
    // ... some code ...
}

四、ThreadLocal其他知识点补充

1. ThreadLocal的原理和特点

  💧ThreadLocal的原理在于利用了Java的双重检查锁定(double-checked locking)机制。在每个线程中,当我们调用get方法时,会首先检查该线程是否已经有了该ThreadLocal变量的副本。如果没有,则进入同步块,再次检查其他线程是否已经创建了该副本。如果还没有,则创建该副本并返回。这种机制使得在多线程环境下,对ThreadLocal变量的访问和修改都能够保证线程安全。

2. ThreadLocal与NIO的关系

  💧NIO(New I/O)是Java提供的一种新的I/O操作方式,它支持非阻塞I/O操作。在NIO中,我们可以使用ThreadLocal来存储每个通道(Channel)的回调函数(Callback)。这样,每个通道都有自己的回调函数副本,从而避免了多个通道之间共享回调函数所带来的问题。

3. ThreadLocal的key

  • ThreadLocal的key是ThreadLocal对象本身。每个ThreadLocal对象内部都有一个Map,用于存储每个线程的变量副本,Map的key是ThreadLocal对象本身value是对应线程的变量副本

  • 在get方法中,先获取当前线程,然后从当前线程对应的Map中获取变量副本,如果不存在则通过initialValue方法初始化一个变量副本并存储到Map中。

  • 在set方法中,也是先获取当前线程,然后将变量副本存储到当前线程对应的Map中。

  • 在remove方法中,先获取当前线程,然后从当前线程对应的Map中移除变量副本。


五、使用ThreadLocal时的注意事项

使用ThreadLocal时需要注意以下几点↓

  1. 💧避免在ThreadLocal中使用过多变量副本,这会消耗额外的内存空间。

ThreadLocal是Java中的一个类,它用于创建线程局部变量。线程局部变量是每个线程都有自己独立的一个变量副本,而这个副本对其他线程是不可见的。这种方式使得多线程下的数据共享变得相对安全。但是,如果我们在ThreadLocal中存储过多的变量副本,就会消耗大量的内存空间。因此,在使用ThreadLocal时,应该尽可能地避免存储过多的变量副本,以避免消耗额外的内存空间。

  1. 💧在使用ThreadLocal时应该及时清理不再使用的变量副本,以避免内存泄漏问题。可以使用弱引用或者软引用来解决内存泄漏问题。

内存泄漏是一种常见的编程问题,它通常发生在长时间运行的程序中。内存泄漏是由于程序在申请内存后,无法释放未再使用的内存空间而导致的。如果内存泄漏持续发生,它将逐渐消耗可用内存,最终导致程序运行缓慢或崩溃。在使用ThreadLocal时,如果不及时清理不再使用的变量副本,就会导致内存泄漏问题的发生。为了解决这个问题,可以使用弱引用或者软引用来替代强引用,从而在对象不再需要时自动释放内存空间。

  1. 💧当不再需要ThreadLocal变量时,应该使用remove方法将其从当前线程的Map中移除,以释放内存空间

在ThreadLocal中,每个线程都有自己独立的变量副本,存储在Map中。当不再需要ThreadLocal变量时,应该及时将其从当前线程的Map中移除,以释放相应的内存空间。可以使用ThreadLocal的remove方法来实现这个操作。这样可以避免内存泄漏问题的发生,同时也可以提高程序的性能。

  1. 💧在使用InheritableThreadLocal时,需要注意变量副本的生命周期问题,避免子线程持有过期的变量副本。可以通过自定义ThreadLocal来实现。

InheritableThreadLocal是ThreadLocal的一个子类,它可以使得子线程继承父线程的变量副本。在使用InheritableThreadLocal时,需要注意变量副本的生命周期问题。如果父线程持有的变量副本已经过期,但是子线程仍然持有这个过期的变量副本,就会导致内存泄漏问题的发生。为了避免这个问题,可以通过自定义ThreadLocal来实现。在自定义的ThreadLocal中,可以维护一个存储变量副本的Map,并记录每个变量副本的生命周期。当变量副本过期时,可以将其从Map中移除。这样就可以避免子线程持有过期的变量副本的问题。


在这里插入图片描述


🐳结语

🐬初学一门技术时,总有些许的疑惑,别怕,它们是我们学习路上的点点繁星,帮助我们不断成长。

🐟积少成多,滴水成河。文章粗浅,希望对大家有帮助!

💧1024 程序员节快乐~

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

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

相关文章

ES挂载不上怎么处理?

全文搜索 EelasticSearch安装 Docker安装 docker run -d --name es7 -e ES_JAVA_POTS"-Xms256m -Xmx256m" -e "discovery.typesingle-node" -v /home/206/es7/data/:/usr/share/elasticsearch/data -p 9200:9200 -p 9300:9300 elasticsearch:7.14.0 …

CANoe-使用IG Ethernet Packet Builder实现IP包分片的若干问题

在文章《CANoe-Ethernet IG和Ethernet Packet Builder的使用和区别》中,我们讲过Packet Builder可以组装多种类型的以太网报文: 当我们想组装一条icmpv4 echo request报文,payload只有1个字节的数据FF时,选择ICMPv4 Packet,创建一条ICMPv4报文,把payload改为1个字节: 然…

【类和对象之构造方法】

文章目录 用构造方法初始化对象格式&#xff1a;public类名特性 快捷键生成构造方法访问修饰限定符总结 用构造方法初始化对象 格式&#xff1a;public类名 注意区分成员方法和构造方法 两者都是在类当中但是成员方法的格式是public返回值方法名参数成员方法有参数&#xff…

Java中整数基础知识

原文链接 Java中整数基础知识 最近做了一道题&#xff0c;非常有意思&#xff0c;题本身很简单&#xff0c;但涉及到整数的最大值以及最小值&#xff0c;当写测试用例的时候&#xff0c;却犯了一个错误&#xff0c;发现最小整数并不是0xFFFFFFFF&#xff0c;我们来仔细看一下。…

网络协议--UDP:用户数据报协议

11.1 引言 UDP是一个简单的面向数据报的运输层协议&#xff1a;进程的每个输出操作都正好产生一个UDP数据报&#xff0c;并组装成一份待发送的IP数据报。这与面向流字符的协议不同&#xff0c;如TCP&#xff0c;应用程序产生的全体数据与真正发送的单个IP数据报可能没有什么联…

Citrix XenDesktop云桌面单点登录XenApp虚拟应用小技巧

哈喽大家好,欢迎来到虚拟化时代君(XNHCYL)。 “ 大家好,我是虚拟化时代君,一位潜心于互联网的技术宅男。这里每天为你分享各种你感兴趣的技术、教程、软件、资源、福利……(每天更新不间断,福利不见不散)” 第1章 前言 实现XenDesktop的桌面打开XenApp发布的应用…

为什么我们从github clone下来的maven项目本地运行报错

github上的项目clone到本地&#xff0c;比如是个Springboot的项目&#xff0c;我们用idea运行莫名其妙的报各种问题&#xff0c;常见的有以下异常&#xff1a; java.lang.NoClassDefFoundError&#xff1a;xxxxjava.lang.ClassNotFoundException:xxxxxjava.lang.NoSuchMethodE…

64 最长公共子序列

最长公共子序列 题解1 DP 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的 最长公共子序列的长度。如果不存在 公共子序列&#xff0c;返回 0 。 一个字符串的子序列是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些…

【CCF】Z字形扫描

这题的关键是将整个扫描的过程&#xff0c;拆分成很多次斜着操作数组的过程。 而且这个过程中可以建立如下规律&#xff1a; &#xff08;1&#xff09;一斜线上的元素个数与切换到下一条斜线这一操作之间建立规律。 先讨论左上部分的数组&#xff1a; 1&#xff09;当元素个…

本地部署Stackedit Markdown编辑器并通过cpolar内网穿透实现远程访问

文章目录 1. docker部署Stackedit2. 本地访问3. Linux 安装cpolar4. 配置Stackedit公网访问地址5. 公网远程访问Stackedit6. 固定Stackedit公网地址 StackEdit是一个受欢迎的Markdown编辑器&#xff0c;在GitHub上拥有20.7k Star&#xff01;&#xff0c;它支持将Markdown笔记保…

指针-Pointer

0.1 地址 &#xff08;1&#xff09;字节&#xff08;Byte) 一个字节存储8位无符号数&#xff08;1Byte 8 bit)&#xff0c;每个字节储存的数值范围为0-255 &#xff08;2&#xff09;内存 1G 1024M 、1M 1024K 、 1K 1024Byte 、1Byte 8 bit &#xff08;3&#xff…

谈谈你对spring boot 3.0的理解

谈谈你对spring boot 3.0的理解 一&#xff0c;Spring Boot 3.0 的兼容性 Spring Boot 3.0 在兼容性方面做出了很大的努力&#xff0c;以支持存量项目和老项目。尽管如此&#xff0c;仍需注意以下几点&#xff1a; Java 版本要求&#xff1a;Spring Boot 3.0 要求使用 Java 1…

高等数学啃书汇总重难点(五)定积分

最近都在忙着刷题&#xff0c;尤其是政治和英语也开始加量复习了&#xff0c;该系列断更了将近2个月~不过最近在刷题的时候又遇到一些瓶颈&#xff0c;因此回归基础来整理一下知史点~ 总的来说&#xff0c;虽然第五章也是重中之重&#xff0c;定理数量也很多&#xff0c;但&…

通过条件竞争实现内核提权

条件竞争漏洞&#xff08;Race Condition Vulnerability&#xff09;是一种在多线程或多进程并发执行时可能导致不正确行为或数据损坏的安全问题。这种漏洞通常发生在多个线程或进程试图访问和修改共享资源&#xff08;如内存、文件、网络连接等&#xff09;时&#xff0c;由于…

There are not enough slots available in the system to satisfy the 48 slots报错

文章目录 问题描述解决办法 问题描述 多核运行时出现这个错误&#xff0c;减少核数运行正常 解决办法 输出命令 vim ~/.bashrc添加 alias mpirunmpirun --oversubscribe执行命令 source ~/.bashrc解决。

imu预积分学习(更新中)

imu预积分学习&#xff08;更新中&#xff09; IMU预积分可以做什么&#xff1f; 以上面那个经典图片为例子&#xff0c;IMU可以通过六轴数据&#xff0c;拿到第i帧和第j帧之间的相对位姿&#xff0c;这样不就可以去用来添加约束了吗 但是有一个比较大的问题是&#xff1a; I…

电脑技巧:27个Office使用小技巧,值得收藏

目录 一、Word 二、EXCEL 三、附文&#xff1a;Word和Excel快捷键 我们中的绝大部分人都使用微软的Office&#xff0c;但是我们是否都了解如何能够最有效地使用它&#xff1f;我们在这里列举了一些关于使用Word和Excel的窍门。 我们使用最多的软件可能就是办公软件了——字…

C++数据结构X篇_19_排序基本概念及冒泡排序(重点是核心代码)

文章目录 1. 排序基本概念2. 冒泡排序2.1 核心代码2.2 冒泡排序代码2.3 查看冒泡排序的时间消耗2.4 冒泡排序改进版减小时间消耗 1. 排序基本概念 现实生活中排序很重要&#xff0c;例如:淘宝按条件搜索的结果展示等。 概念 排序是计算机内经常进行的一种操作&#xff0c;其目…

计算机网络(谢希仁)第八版课后题答案(第一章)

1.计算机网络可以向用户提供哪些服务 连通性:计算机网络使上网用户之间可以交换信息&#xff0c;好像这些用户的计算机都可以彼此直接连通一样。 共享:指资源共享。可以是信息、软件&#xff0c;也可以是硬件共享。 2.试简述分组交换的要点 采用了存储转发技术。把报文(要发…

Python 测试框架unittest和pytest的优劣

一、Unittest Unittest是Python标准库中自带的单元测试框架&#xff0c;Unittest有时候也被称为PyUnit&#xff0c;就像JUnit是Java语言的标准单元测试框架一样&#xff0c;Unittest则是Python语言的标准单元测试框架。 Unittest支持自动化测试&#xff0c;测试用例的初始化、…