JUC 之 线程局部变量 ThreadLocal

news2024/9/28 5:30:25

—— ThreadLocal

基本概念

  • ThreadLocal 提供线程局部变量。这些变量与正常的变量不同,因为每一个线程在访问 ThreadLocal 实例的时候(通过其get 或者 set 方法)都有自己的、独立初始化的变副本。ThreadLocal实例通常是类中的私有静态字段,使用它的目的是希望将状态(例如:用户Id或者 事务ID)与线程关联起来
  • 实现每一个线程都有自己专属的本地变量副本,主要解决了让每个线程绑定自己的值,通过get 和 set 方法,获取默认值或将其值更改为当前线程所存的副本的值从而避免了线程安全问题
  • 既然其他 Thread 不访问,那就不存在多线程之间的共享问题
  • 统一设置初始值但是每个线程对这个值的修改都是各自线程互相独立的

Thread、ThreadLocal、ThreadLocalMap 三者关系

  • ThreadLocalMap 实际上就是一个以 ThreadLocal 实例为 key,任意对象为 value 的 Entry 对象
  • 当我们为 ThreadLocal 变量赋值,实际上就是以当前 ThreadLocal 实例为 key,值为 value 的 Entry 往这个 ThreadLocalMap 中存放
  • Jvm 内部维护了一个线程版的 Map<ThreadLocal,Value>,每个线程要用到这个 T 的时候,用当前的线程去 Map 里面获取,通过这样让每个线程都拥有了自己独立的变量,人手一份,竞争条件被彻底消除,在并发模式下是绝对安全的变量

引发内存泄露问题

  • 内存泄露:不再会被使用的对象或者变量占用的内存不能被回收
  • ThreadLocalMap 从字面可以看出这是一个保存 ThreadLocal 对象的 map(以 ThreadLocal 为 key),不过是经过了两层包装的 ThreadLocal 对象
    • 第一层包装是使用 WeakReference<ThreadLocal<?>> 将 ThreadLocal 对象变成一个弱引用对象
    • 第二层包装是定义了一个专门的类 Entry 来扩展WeakReference<ThreadLocal<?>>
  • 强引用:当内存不存,JVM 开始垃圾回收,对于强引用的对象,就算出现了 OOM 也不会对该对象进行回收;最常见的普通对象引用,只要还有强引用指向一个对象,就表明对象活着,除非为null。因此强引用是造成内存泄露的主要原因之一
  • 软引用:相对强引用弱化,用java.lang.ref.SoftReference实现,通常用在对内存敏感的程序中,比如高速缓存就需要软引用;JVM 内存充足时它不会被回收,不足时会被回收
  • 弱引用:用java.lang.ref.WeakReference实现,比软引用的生存期更短,只要垃圾回收机制一运行, 不管JVM 的内存空间是否足够,都会被回收
    • 软引用 和 弱引用的适用场景:读取大量的本地图片
      • 如果每次读取图片从硬盘读取影响性能;一次性全部加载到内存中可能造成内存溢出
      • 软引用可解决该问题:用 HashMap<String,SoftReference<BitMap>> 来保存图片的路径和响应的图片对象关联的软引用之间的映射关系,在内存不足时,JVM 会自动回收这些缓存图片对象所占用的空间,从而有效避免 OOM 的问题
  • 虚引用:用java.lang.ref.PhantomReference实现
    • 必须和引用队列(ReferenceQueue)联合使用,形同虚设;一个对象仅持有虚引用,那么它和没有任何引用一样,在任何时候都可能被垃圾回收器回收
    • PhantomReference 的get方法总是返回 null,因此无法访问对象的引用对象
    • 设置虚引用的唯一目的,就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步的处理
  • 为什么使用弱引用?不用有什么后果
    • 当线程方法执行完毕后,栈帧销毁强引用 tl 就没有了,但此时线程的ThreadLocalMap 里某个 entry 的key 引用还指向这个对象
    • 若 key 为强引用,导致key 指向的 ThreadLocal 对象 和 v 不能被 GC,造成内存泄露
    • 若 key 为弱引用就大概率减少内存泄露的问题,使用弱引用,就可以使 ThreadLocal 对象在方法执行完毕后顺利回收且Entry的key引用指向为null
      在这里插入图片描述
  • 当 key 引用指向为null时,同样会引发内存泄露!!
    • 当ThreadLocalMap 中出现 key 为null 的 Entry ,就没有办法访问这些 key 为 null 的 Entry 的value,如果当前线程迟迟不结束的话,这些 key 为 null 的 Entry-value 就会一直存在一条强引用链(Thread Ref 》 Thread 》 ThreadLocalMap 》 Entry 》 value),永远无法回收,造成内存泄露
    • 如果当前 Thread 结束,Entry 没有引用链可达,在垃圾回收的时候就会被系统进行回收
    • 但在实际应用中,我们会用线程池维护我们的线程,比如在Executors.newFixedThreadPool()时创建线程时,为了复用线程是不会结束的,所以ThreadLocal内存泄露就值得注意
    • 解决:要在不适用某个 ThreadLocal 对象后,手动调用 remove 方法来删除(remove方法会寻找脏 Entry(key=null) ,然后进行删除)

最佳实践方式

  • 使用 ThreadLocal.withInitial(() -> 初始化值) 初始化
  • 建议把 ThreadLocal 修饰为 static (ThreadLocal 只需要初始化一次,不需要多次)
  • 手动调用 remove
  • ThreadLocal 适用于变量在线程间隔离且在方法间共享的场景
  • ThreadLocal 并不解决线程间共享数据的问题
  • ThreadLocal 通过隐式的在不同线程内创建独立实例副本避免了实例线程安全的问题

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

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

相关文章

104-JVM优化

JVM优化为什么要学习JVM优化&#xff1a; 1&#xff1a;深入地理解 Java 这门语言 我们常用的布尔型 Boolean&#xff0c;我们都知道它有两个值&#xff0c;true 和 false&#xff0c;但你们知道其实在运行时&#xff0c;Java 虚拟机是 没有布尔型 Boolean 这种类型的&#x…

@Autowired和@Resource的区别

文章目录1. Autowired和Resource的区别2. 一个接口多个实现类的处理2.1 注入时候报错情况2.2 使用Primary注解处理2.3 使用Qualifer注解处理2.4 根据业务情况动态的决定注入哪个serviceImpl1. Autowired和Resource的区别 Aurowired是根据type来匹配&#xff1b;Resource可以根…

数据结构栈的经典OJ题【leetcode最小栈问题大剖析】【leetcode有效的括号问题大剖析】

目录 0.前言 1.最小栈 1.1 原题展示 1.2 思路分析 1.2.1 场景引入 1.2.2 思路 1.3 代码实现 1.3.1 最小栈的删除 1.3.2 最小栈的插入 1.3.3 获取栈顶元素 1.3.4 获取当前栈的最小值 2. 有效的括号 0.前言 本篇博客已经把两个关于栈的OJ题分块&#xff0c;可以根据目…

【蓝牙mesh】Upper协议层介绍

【蓝牙mesh】Upper协议层介绍 Upper层简介 Upper协议层用于处理网络层以上的功能&#xff0c;包括设备的应用层数据、安全、群组等信息&#xff0c;是实现蓝牙mesh应用功能的关键协议之一。Upper层接收来自Access层的数据或者是Upper层自己生成的Control数据&#xff0c;并且将…

typing库

typing 库 引入 在日常代码编写中&#xff0c;由于python语言特性&#xff0c;不用像go等编译性语言一样&#xff0c;在定义函数时就规范参数和放回值的类型。 def demo(a, b):return "ab" 此时 a 和 b 可以传入任意类型参数毫无疑问&#xff0c;这一特性&#…

漏洞分析: WSO2 API Manager 任意文件上传、远程代码执行漏洞

漏洞描述 某些WSO2产品允许不受限制地上传文件&#xff0c;从而执行远程代码。以WSO2 API Manager 为例&#xff0c;它是一个完全开源的 API 管理平台。它支持API设计&#xff0c;API发布&#xff0c;生命周期管理&#xff0c;应用程序开发&#xff0c;API安全性&#xff0c;速…

【RockerMQ】001-RockerMQ 概述

【RockerMQ】001-RockerMQ 概述 文章目录【RockerMQ】001-RockerMQ 概述一、MQ 概述1、MQ 简介2、MQ 用途限流削峰异步解耦数据收集3、常见 MQ 产品概述对比4、MQ 常见协议二、RocketMQ 概述1、简介2、发展历史一、MQ 概述 1、MQ 简介 MQ&#xff0c;Message Queue&#xff0…

C++设计模式(22)——状态模式

亦称&#xff1a; State 意图 状态模式是一种行为设计模式&#xff0c; 让你能在一个对象的内部状态变化时改变其行为&#xff0c; 使其看上去就像改变了自身所属的类一样。 问题 状态模式与有限状态机 的概念紧密相关。 有限状态机。 其主要思想是程序在任意时刻仅可处…

【数据库】数据库的完整性

第五章 数据库完整性 数据库完整性 数据库的完整性是指数据的正确性和相容性 数据的正确性是指数据是符合现实世界语义&#xff0c;反映当前实际状况的数据的相容性是指数据库的同一对象在不同的关系中的数据是符合逻辑的 关系模型中有三类完整性约束&#xff1a;实体完整性…

中创公益|中创算力荣获“2022年度突出贡献爱心企业”

公益是什么&#xff1f;不啻微芒造炬成阳萤火虽微愿为其芒公益是持之以恒的努力&#xff0c;中创于2021年1月成立&#xff0c;同年4月中创就开始了公益活动&#xff0c;并对尖山村贫困儿童进行定期捐助。截至2023年&#xff0c;中创先后7次来到被捐助的贫困儿童家中&#xff0c…

【Git】IDEA整合Git详细步骤 — IDEA如何配置Git忽略文件

目录 一、IDEA整合Git 定位 Git 程序 —》IDEA配置Git程序 初始化本地库—》在idea中初始化项目&#xff0c;将项目纳入git管理 添加到暂存区 提交到本地库 方法一: 右键点击项目---> Git ----> Commit Directory 方法二: 点击绿色图标 √ 切换版本 创建分支 切换分…

chatgpt的原理 第一部分

前言 这两天&#xff0c;ChatGPT模型真可谓称得上是狂拽酷炫D炸天的存在了。一度登上了CSDN热搜&#xff0c;这对科技类话题是非常难的存在。不光是做人工智能、机器学习的人关注&#xff0c;而是大量的各行各业从业人员都来关注这个模型&#xff0c;真可谓空前盛世。 我赶紧把…

无人驾驶路径规划论文简要

A Review of Motion Planning Techniques for Automated Vehicles综述和分类0Motion Planning for Autonomous Driving with a Conformal Spatiotemporal Lattice从unstructured环境向structured环境的拓展&#xff0c;同时还从state lattice拓展到了spatiotemporal lattice从而…

【数据结构】双向链表的接口实现(附图解和源码)

双向链表的接口实现&#xff08;附图解和源码&#xff09; 文章目录双向链表的接口实现&#xff08;附图解和源码&#xff09;前言一、定义结构体二、接口实现&#xff08;附图解源码&#xff09;1.初始化双向链表2.开辟新空间3.尾插数据4.尾删数据5.打印双向链表中数据6.头插数…

含分布式电源的配电网日前两阶段优化调度模型(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…

吃瓜教程笔记—Task04

神经网络 知识点 M-P神经元 模型如图所示&#xff1a;  神经元的工作机理&#xff1a;神经元接收来到n个其他神经元传递过来的输入信号&#xff0c;这些输入信号通过带权重的连接进行传递&#xff0c;神经元接收到的总输入值将与神经元的阈值进行比较&#xff0c;然后通过…

Tesla Autopilot,处理器和硬件

作者 | 初光 出品 | 车端 备注 | 转载请阅读文中版权声明 知圈 | 进“汽车电子与AutoSAR开发”群&#xff0c;请加微“cloud2sunshine” 总目录链接>> AutoSAR入门和实战系列总目录 Tesla MOdelS/X 中有 60 多个处理器。其他型号的处理器较少&#xff0c;但数量仍然不少…

Nginx 全局变量

变量说明$host 域名部分 www.baidu.com/1.php?a1&b2 $document_uri 当前请求中不包含参数的uri www.baidu.com/1.php?a1&b2 $uri和 $document_uri 一样$args 请求中的参数。 www.baidu.com/1.php?a1&b2 $args是a1&b2 $request_uri 请求的URI。 www.baidu.co…

K8S常用命令速查手册

K8S常用命令速查手册一. K8S日常维护常用命令1.1 查看kubectl版本1.2 启动kubelet1.3 master节点执行查看所有的work-node节点列表1.4 查看所有的pod1.5 检查kubelet运行状态排查问题1.6 诊断某pod故障1.7 诊断kubelet故障方式一1.8 诊断kubelet故障方式二二. 端口策略相关2.1 …

UVM仿真环境搭建

环境 本实验使用环境为&#xff1a; Win10平台下的Modelsim SE-64 2019.2 代码 dut代码&#xff1a; module dut(clk,rst_n, rxd,rx_dv,txd,tx_en); input clk; input rst_n; input[7:0] rxd; input rx_dv; output [7:0] txd; output tx_en;reg[7:0] txd; reg tx_en;always…