Java:ThreadLocal解析

news2024/11/23 22:11:29

Java:ThreadLocal解析

  • 前言
  • 一、 什么是ThreadLocal?
  • 二、ThreadLocal的内存泄漏问题
    • 1.什么是内存泄漏?
    • 2.为什么会出现内存泄漏问题?
    • 3.如何解决内存泄漏问题?
      • (1)ThreadLocal会自动清除key为null的value
      • (2)使用完毕后及时调用ThreadLocal.remove()
      • (3)把ThreadLocal设置为全局变量
  • 三、Entry的key可以设置为强引用吗?
  • 三、Entry的value可以设置为弱引用吗?


前言

ThreadLocal 是java中非常重要的内容,本文尽可能的全面介绍了 ThreadLocal内容,包括内存泄漏,key弱引用等问题


一、 什么是ThreadLocal?

第一种解释:ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量

第二种解释:一个ThreadLocal在一个线程中是共享的,在不同线程之间又是隔离的”,每个线程都只能看到自己线程的值,这也就是 ThreadLocal的核心作用:实现线程范围的局部变量。

第三种解释:ThreadLocal 类主要解决的就是让每个线程绑定自己的值,可以将 ThreadLocal 类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。

如果你创建了一个 ThreadLocal 变量,那么访问这个变量的每个线程都会有这个变量的本地副本,这也是 ThreadLocal 变量名的由来。他们可以使用 get() 和 set() 方法来获取默认值或将其值更改为当前线程所存的副本的值,从而避免了线程安全问题。

在这里插入图片描述
在这里插入图片描述
总结:Thread线程可以拥有多个ThreadLocal维护的自己线程独享的共享变量(这个共享变量只是针对自己线程里面共享)
在这里插入图片描述

在这里插入图片描述

二、ThreadLocal的内存泄漏问题

1.什么是内存泄漏?

内存泄漏为程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,因为无论多少内存,迟早会被占光。
广义并通俗的说,就是:不再会被使用的对象或者变量占用的内存不能被回收,就是内存泄露。

2.为什么会出现内存泄漏问题?

在这里插入图片描述

ThreadLocal操作不当会引发内存泄露,最主要的原因在于它的内部类ThreadLocalMap中的Entry的设计。

Entry继承了WeakReference<ThreadLocal<?>>,即Entry的key是弱引用,弱引用的特点是,如果这个对象只存在弱引用,那么在下一次垃圾回收的时候必然会被清理掉。所以key会在垃圾回收的时候被回收掉, 而key对应的value则不会被回收, 这样会导致一种现象:key为null,value有值。

key为空的话value是无效数据,久而久之,value累加就会导致内存泄漏。

ThreadLocal在没有外部对象强引用时如Thread,发生GC时弱引用Key会被回收,而Value是强引用不会回收,如果创建ThreadLocal的线程一直持续运行如线程池中的线程,那么这个Entry对象中的value就有可能一直得不到回收,发生内存泄露
在这里插入图片描述

从上图中可以看出,hreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal不存在外部强引用时,Key(ThreadLocal)势必会被GC回收,这样就会导致ThreadLocalMap中key为null, 而value还存在着强引用,只有thread线程退出以后,value的强引用链条才会断掉。

但如果当前线程再迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:

Thread Ref --> Thread  -->ThreaLocalMap  --> Entry -->value

即永远无法回收,造成内存泄漏。

需要特别强调的时候,entry对于key即 threadlocal 的引用是弱引用,对 value 的引用是强引用,但是外部对于 threadlocal 的引用是强引用。
因此,当外部引用 threadlocal 的时候,threadlocal 不会被GC回收,因为有强引用,但是当外部不再引用 threadlocal 的时候,即

 threadlocal = null

此时 threadlocal 就只有entry 的弱引用,会被回收

3.如何解决内存泄漏问题?

(1)ThreadLocal会自动清除key为null的value

ThreadLocal的get()、set()、remove()的时候都会清除线程ThreadLocalMap里所有key为null的value。

(2)使用完毕后及时调用ThreadLocal.remove()

emove方法会主动将当前的key和value(Entry)进行清除。
在这里插入图片描述

(3)把ThreadLocal设置为全局变量

ThreadLocal设置为全局变量使得它无法被GC回收(如果在成员变量 中使用就将修饰符设置为public static,ThreadLocal不会被回收也就不会存在key为null的情况, 也就不会内存泄漏)

三、Entry的key可以设置为强引用吗?

不可以!

当ThreadLocalMap的key为强引用,回收ThreadLocal时因为ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏

要知道,ThreadlocalMap是和线程绑定在一起的,如果这样线程没有被销毁,而我们又已经不会再某个threadlocal引用,那么key-value的键值对就会一直在map中存在,这对于程序来说,就出现了内存泄漏。

为了避免这种情况,只要将key设置为弱引用,那么当发生GC的时候,就会自动将弱引用给清理掉,也就是说:假如某个用户A执行方法时产生了一份threadlocalA,释放了threadlocalA后,作为弱引用,它会在下次垃圾回收时被清理掉。

而且ThreadLocalMap在内部的set,get和扩容时都会清理掉泄漏的Entry,内存泄漏完全没必要过于担心。

三、Entry的value可以设置为弱引用吗?

不可以!

假如value被设计成弱引用,那么很有可能当你需要取这个value值的时候,取出来的值是一个null。

你使用ThreadLocal的目的就是要把这个value存储到当前线程中,并且希望在你需要的时候直接从当前线程中拿出来,那么意味着你的value除了当前线程对它持有强引用外,理论上来说,不应该再有其他强引用,否则你也不会把value存储进当前线程。但是一旦你把本应该强引用的value设计成了弱引用,那么只要jvm执行一次gc操作,你的value就直接被回收掉了。当你需要从当前线程中取值的时候,最终得到的就是null。

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

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

相关文章

层级在BW4HANA中的处理

目录 1.从flatfile加载层级的处理 2. 从ERP数据源抽取区间层级到BW 2.1 在ERP中的层级数据源 2.1.1 PSA格式和IDoc格式的区别 2.1.2 怎么查看Interval的字段 2.1.3 如何在S4里查看层级数据源结构 2.1.4 关于时间相关层级date to和date from 1.从flatfile加载层级的处理 层…

【快速开始】一个简单的Flask-SocketIO应用,完成后端推送消息接收与关闭

效果图 先看运行效果图 OK&#xff0c;下面开始。 安装环境 本人使用环境及版本&#xff1a; Anaconda&#xff1a; 虚拟环境&#xff1a; Python版本&#xff1a;3.8.13 安装包及版本&#xff1a; Flask-SocketIO&#xff1a;5.3.4 eventlet&#xff1a;0.33.3 快速开…

BUU [ZJCTF 2019]NiZhuanSiWei

BUU [ZJCTF 2019]NiZhuanSiWei 先看题目&#xff0c;提示了useless.php。 猜到了flag在哪。 没啥可以学的&#xff0c;直接上exp。 ?textdata://text/plain,welcome to the zjctf &filephp://filter/readconvert.base64-encode/resourceuseless.php &passwordO:4:&q…

工作学习总结:安卓地图SDK测试--前置准备阶段8天

工作学习总结&#xff1a;安卓地图SDK测试--前置准备阶段8天 安卓地图SDK测试--前置准备阶段8天前置知识&#xff1a;1、安卓环境开发部署2、高德 SDK demo 如何进行调试&#xff08;1&#xff09;SHA1 密钥无法获取&#xff08;2&#xff09;下载了高德 3D 地图 demo&#xff…

Leetcode---352周赛

周赛题目 2760. 最长奇偶子数组 2761. 和等于目标值的质数对 2762. 不间断子数组 2763. 所有子数组中不平衡数字之和 一、最长奇偶子数组 这题的数据范围允许用暴力来做&#xff0c;只要我们分别枚举左端点left和右端点right&#xff0c;然后看区间[left,right]是否符合题目条…

stable diffusion 百宝书

文章目录 0. 环境搭建0.1 Windows0.1.1 git环境安装0.1.2 python 环境搭建0.1.2.1 配置pip国内镜像源 0.1.3 stable diffusion环境搭建0.1.3.1 远程访问Stable diffusion0.1.3.2 模型 Lora下载 1. 基础知识1.1 Stable Diffusion Webui及基础参数1.2 参数说明1.2.1 采样方法1.2.…

【AI实战】从零开始搭建中文 LLaMA-33B 语言模型 Chinese-LLaMA-Alpaca-33B

【AI实战】从零开始搭建中文 LLaMA-33B 语言模型 Chinese-LLaMA-Alpaca-33B 简介环境配置环境搭建依赖安装 代码及模型权重拉取拉取 Chinese-LLaMA-Alpaca拉取 llama-30b-hf 模型权重及代码拉取 chinese-llama-lora-33b 模型权重及代码 合并模型权重先转换 pth 类型的模型权重&…

docker版jenkins安装node打包vue2

下载node 通过jenkins配置下载因为某些原因会失败&#xff0c;故自己下载安装https://nodejs.org/zh-cn/download解压然后复制到docker的jenkins容器 tar -xvf node-v16.18.1-linux-x64.tar.xzdocker cp ./node-v16.18.1-linux-x64 jenkins:/node配置 jenkins-全局工具配置- …

【Vim编辑器】编码技巧:模板(自动添加信息)+配置参考(~/.vimrc)

前言&#xff1a; 在编写代码时&#xff0c;为了提高代码的可读性和维护性&#xff0c;我们经常在文件的头部添加一些信息提示&#xff0c;如作者、日期、版本号等。本文介绍了如何在 Vim 编辑器中实现自动添加信息提示的功能。 结尾提供~/.vimr参考配置&#xff0c;可提高代码…

短视频seo矩阵+抖音小程序源码开源部署(二)

一、 开发思路&#xff1a; 通过短视频seo矩阵抖音小程序的形式&#xff0c;实现视频的批量制作&#xff0c;小程序内容批量挂载&#xff0c;客户线索批量收集&#xff0c;实现企业运营价值最大化。开发逻辑&#xff1a;通过短视频矩阵布局seo搜索关键词&#xff0c;接入小程序…

Elasticsearch:文档版本控制和乐观并发控制

在今天的文章中&#xff0c;我来详细描述一下 Elasticsearch 文档的版本控制以及如何更新文档。你也可以阅读我之前的文章 “Elasticsearch&#xff1a;深刻理解文档中的 verision 及乐观并发控制”。 版本控制 我们知道 Elasticsearch 的每个文档都有一个相对应的版本。这个版…

GO微服务简介及特性介绍

微服务特性 一、微服务简介-构建单体应用 互联网技术发展迅速的今天&#xff0c;微服务倍受关注&#xff1a;文章、博客、社交媒体讨论和会议演讲都在谈论。与此同时&#xff0c;也有持怀疑态度的软件社区人员认为微服务没什么新鲜可言。反对者声称它的思想只是面向服务架构的…

Windows系统安装JAVA步骤流程(超详细)

超详细的Windows系统安装JAVA步骤流程&#xff0c;Windows操作系统安装java&#xff0c;先下载JDK&#xff0c;然后配置环境变量&#xff0c;阿里云百科分享详细安装流程如下&#xff1a; 目录 Window操作系统安装java流程 下载JDK 配置环境变量 JAVA_HOME 设置 PATH设置…

Centos安装RabbitMQ

#安装 yum install rabbitmq-server #启动 systemctl start rabbitmq-server #查看状态 systemctl status rabbitmg-server #安装管理插件 rabbitmg-plugins enable rabbitmg_management #新增admin账号 rabbitmqctl add_user admin admin #设置为管理员 rabbitmqctl set_user_…

电子电气架构——车载DoIP通信

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 人们会在生活中不断攻击你。他们的主要武器是向你灌输对自己的怀疑:你的价值、你的能力、你的潜力。他们往往会将此伪装成客观意见,但无一例外的是…

基于FreeRTOS的嵌入式设备管理关键技术研究及实现(学习二)

嵌入式操作系统FreeRTOS FreeRTOS是一个专门为轻量级嵌入式应用设计的迷你操作系统&#xff0c;它的主要功能由IPC、时钟管理、内存管理、任务通知以及任务调度等部分构成。 FreeRTOS的代码可以分解为三个主要区块&#xff1a;任务调度、通讯、硬件库。 任务调度&#xff1a;F…

windows环境安装robotframework-ride

在Windows环境下&#xff0c;可以通过以下步骤安装Robot Framework RIDE&#xff1a; 安装Python 首先&#xff0c;需要在Windows环境下安装Python。建议使用Python 3.x版本&#xff0c;可以从官方网站下载并安装&#xff1a;https://www.python.org/downloads/windows/ 安装w…

shiro登录认证

一&#xff0c;创建数据库 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0; -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS user; CREATE TABLE user ( uid int(11) NOT NULL AUTO_INCREMENT, uname va…

opencv中Rect()类与rectangle()函数详解

文章目录 Rect()矩形类1、实例化 Rect() 类&#xff1a;&#xff08;1&#xff09;构造函数&#xff1a; 2、Rect类的成员函数&#xff08;1&#xff09;rect.size() 和 rect.area() 和 rect.width() 和 rect.height()&#xff0c;用来描述矩形的宽度&#xff0c;高度&#xff…

SQL专家云回溯某时间段内的阻塞

背景 SQL专家云像“摄像头”一样&#xff0c;对环境、参数配置、服务器性能指标、活动会话、慢语句、磁盘空间、数据库文件、索引、作业、日志等几十个运行指标进行不同频率的实时采集&#xff0c;保存到SQL专家云自己的数据库中。因此可以随时对任何一个时间段进行回溯。 趋势…