线程进阶-2 ThreadLocal

一.简单说一下ThreadLocal

1.ThreadLocal是一个线程变量,用于在并发条件下,为不同线程提供相互隔离的变量存储空间。在多线程并发的场景下,每个线程往ThreadLocal中存的变量都是相互独立的。

2.基本方法

(1)set(Object v):将变量与当前线程绑定。

(2)get():获取当前线程绑定的变量

(3)remove():移除当前线程绑定的变量

二.synchronized和ThreadLocal的区别

synchronized和ThreadLocal都是用于解决多线程并发访问共享变量的情况。

1.原理:

(1)synchronized是通过加锁的方式,只提供一份变量,每次只让一个线程访问该变量;上一个线程对变量的访问结果会影响下一个访问变量的线程

(2)ThreadLocal是对变量进行拷贝,每一个线程都往自己的空间中存一份共享变量的副本,多线程可同时访问各自的副本变量。且由于线程空间相互隔离,线程对副本变量的修改不会对其他线程产生影响

2.侧重点:

(1)synchronized主要用于多线程间访问资源的同步,保证了并发编程的原子性和可见性;但并发效率下降。

(2)ThreadLocal主要用于同一个线程在上下执行逻辑间传递数据,保证了多线程间数据的隔离。

三.说一下ThreadLocal的内部结构

1.jdk1.7:

(1)一个ThreadLocal内部有一个Map(ThreadLocalMap)用于存储数据。

(2)ThreadLocalMap的key是线程Thread,value是该线程绑定的变量副本。

(3)线程每次要访问变量,都要到ThreadLocal中,以自己为映射找到对应的变量。

2.jdk1.8:

(1)每一个线程Thread内部都有一个Map(ThreadLocalMap)用于存储数据。

(2)ThreadLocalMap的key是ThreadLocal,value是该线程绑定的副本变量。

(3)线程每次要访问变量,都要到自己的空间中,以当时绑定的ThreadLocal对象作为key映射,找到对应的变量。

3.jdk1.8把ThreadLocalMap存在Map中的好处

(1)降低哈希冲突的概率。jdk1.8的ThreadLocalMap是用ThreadLocal对象作为key,jdk1.7的ThreadLocalMap是用Thread对象作为key,通常程序中ThreadLocal对象的数量要明显少于Thread对象的数量,则ThreadLocalMap要存储的元素就减少,发生哈希冲突的概率就会下降。

(2)提高内存利用率。ThreadLocalMap在Thread中,则当Thread销毁时对应的ThreadLocalMap也会被销毁。但若是ThreadLocalMap在ThreadLocal中,则只要ThreadLocal还存在,即使Thread都销毁了,对应的ThreadLocalMap仍然存在占据空间。

四.说一下ThreadLocal的底层原理

1.set(T value):

(1)获取当前线程

(2)如果当前线程的ThreadLocalMap不为空,则以键值对ThreadLocal:value存入。

(3)如果当前ThreadLocalMap为空,则先创建一个ThreadLocalMap,再将ThreadLocal:value存入。

2.get():

(1)获取当前线程

(2)如果当前线程的ThreadLocalMap不为空,则以ThreadLocal为键,索引到对应节点Entry e

(3)如果e不为null,则直接将e返回

(4)如果当前线程的ThreadLocalMap为null 或 获取到的e为null,则调用setInitialMap()方法:若ThreadLocalMap为null,则创建ThreadLocalMap,并将键值对ThreadLocal:initialValue()存入后返回;如果e为null,则将键值对ThreadLocal:initialValue()存入后返回。即最终返回的都是initialValue()。

3.initialValue():

(1)直接返回一个null

(2)也就是说对于get()方法中ThreadLocalMap为null或者索引到的Entry为null时,都会以ThreadLocal:null存入,并将null返回;只有当第一次调用set(T value)时才会将null值覆盖。

(3)可以通过重写initialValue()方法,设置存入的初始值不为null。

4.remove():

(1)获取当前线程

(2)如果当前线程的ThreadLocalMap不为null,则将索引到的Entry移除。

五.说一下ThreadLocal的内存泄露情况

1.ThreadLocalMap的引用情况:

(1)ThreadLocalMap是Thread的一个属性,Thread对ThreadLocalMap是强引用;ThreadLocalMap对里面的每一个节点Entry也是强引用。即存在强引用链:Thread——ThreadLocalMap——Entry。

(2)ThreadLocal是ThreadLocalMap的键,ThreadLocalMap对ThreadLocal是弱引用。

2.如果ThreadLocalMap对ThreadLocal是强引用:

(1)当栈中其他对ThreadLocal的引用销毁,由于ThreadLocalMap对ThreadLocal是强引用,因此ThreadLocal在堆中无法被回收,有OOM的风险。

(2)栈中其他对ThreadLocal的引用销毁,则ThreadLocalMap中该ThreadLocal对应的Entry也就没有意义;但由于ThreadLocalMap对Entry是强引用,因此该Entry无法被回收,有OOM的风险。

3.如果ThreadLocalMap对ThreadLocal是弱引用:

(1)当栈中其他对ThreadLocal的引用销毁,由于ThreadLocalMap对ThreadLocal是弱引用,因此ThreadLocal在堆中可以被回收。回收后ThreadLocalMap对应的键就会变回null,但值Entry仍然存在。

(2)ThreadLocal被回收,则ThreadLocalMap中该ThreadLocal对应的Entry也就没有意义;但由于ThreadLocalMap对Entry是强引用,因此该Entry无法被回收,有OOM的风险。

4.可以看出:无论ThreadLocalMap对ThreadLocal是强引用还是弱引用,都会有OOM的风险,因为ThreadLocalMap会导致OOM的根本原因是存在强引用链Thread——ThreadLocalMap——Entry,导致Entry的生命周期和Thread一样长,若不手动删除对应的Entry就会有OOM的风险。

5.因此使用ThreadLocal时为了避免OOM,一定要调用remove()手动删除对应的Entry。

六.无论ThreadLocalMap对ThreadLocal是强引用还是弱引用都会导致OOM,那选择弱引用的原因是什么?

1.ThreadLocalMap对ThreadLocal是弱引用,则当外部没有其他对ThreadLocal的强引用时,堆中的ThreadLocal可以被顺利回收。提高内存利用率。

2.ThreadLocal被回收后,其在ThreadLocalMap中对应的键会变成null,变成了幽灵键。而ThreadLocal的set()、get()、remove()等方法在执行时会进行迭代检查,若检测到幽灵键则会将对应的Entry移除。降低了OOM的风险。

七.ThreadLocalMap中解决哈希冲突的方式是什么?

线性探测法

1.若将ThreadLocal作为key哈希映射到的槽位已被占用,且占用槽位的ThreadLocal和当前ThreadLocal不是同一个对象,则当前索引加一,继续判断下一个。若索引到达最后一个仍不满足,则索引归零,重新开始往后判断,直到找到一个槽位为null,可存储;或者找到占用槽位的ThreadLocal和当前ThreadLocal为同一个对象,可覆盖。

2.ThreadLocalMap的扩容阈值threshold是length*(2/3),因此不会出现把整个Map都遍历一遍仍然找不到槽位存储的情况。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

wms中对屏幕进行修改wm size设置屏幕宽高原理剖析

背景: 上面是正常屏幕1440x2960的屏幕大小,如果对display进行相关的修改,可以使用如下命令: adb shell wm size 1080x1920 得出如下的画面 明显看到差异就是屏幕上下有黑边了,那么下面就来调研这个wm size是怎么做的…

软件系统测试的定义和测试内容介绍

一、什么是软件系统测试? 软件系统测试是指对软件系统的功能、性能、可靠性、稳定性等方面进行全面检查和验证的过程。其目的是发现潜在的问题、缺陷和风险,并确保软件系统的质量和稳定性。 软件系统测试可以分为多个阶段,包括单元测试、集成测试、系…

《深入浅出C语言:从基础到指针的全面指南》

1. 简介 C语言是一种通用的编程语言,广泛应用于系统编程、嵌入式系统和高性能应用程序。它由Dennis Ritchie在1972年开发,并且至今仍然非常流行。C语言以其高效、灵活和强大的功能著称,是许多现代编程语言的基础。 2. 基本语法 2.1 Hello, …

44-4 waf绕过 - CDN简介

一、CDN简介 CDN,即内容分发网络(Content Delivery Network),是建立在现有网络基础之上的智能虚拟网络。它依靠部署在各地的边缘服务器,并通过中心平台的负载均衡、内容分发和调度等功能模块,使用户可以就近获取所需内容,从而降低网络拥塞,提高用户访问响应速度和命中率…

servlet小项目与servlet续集

文章目录 servlet小项目与servlet续集,是结合上一次的案例进行升级,给项目新增了,增加员工,删除员工,查询具体员工 功能新增操作修改操作删除操作过滤器Cookie servlet小项目与servlet续集,是结合上一次的案例进行升级,给项目新增了,增加员工,删除员工,查询具体员工 功能 上一…

Spring boot集成通义千问大模型实现智能问答

Spring boot集成通义千问大模型实现智能问答 背景 我在用idea进行java开发时发现了通义灵码这款免费的智能代码补全插件,用了一段时间了,感觉很不错。就想着在自己的项目中也能集成通义千问大模型实现智能回答,毕竟对接openai需要解决网络问…

社交媒体数据恢复:Weico

一、从备份中恢复数据 云备份 希望这篇教程能帮助你恢复Weico中的聊天记录和文件。如有其他问题,请随时联系我们。 三、注意事项 在尝试恢复数据的过程中,请避免执行任何可能导致数据进一步丢失的操作。 数据恢复的效果取决于多种因素,包…

GPU的最佳拍档HBM到底是什么

在AI界,英伟达的大名无人不知,无人不晓。然而即使在AI芯片界占据绝对霸主地位的英伟达,依旧受制于人。 众所周知,算力与带宽是制衡AI应用的两大关键因素,长期以来高速发展的算力受困于有限的带宽限制了其性能的最大发…

信息系统项目管理师0142:管理新实践(9项目范围管理—9.1管理基础—9.1.2管理新实践)

点击查看专栏目录 文章目录 9.1.2 管理新实践 9.1.2 管理新实践 需求一直是项目管理的关注重点,需求管理过程结束于需求关闭,即把产品、服务或成果移交给接收方,以便长期测量、监控、实现并维持收益。随着全球项目环境变得日益复杂&#xff0…

【人工智能Ⅱ】实验8:生成对抗网络

实验8:生成对抗网络 一:实验目的 1:理解生成对抗网络的基本原理。 2:学会构建改进的生成对抗网络,如DCGAN、WGAN、WGAN-GP等。 3:学习在更为真实的数据集上应用生成对抗网络的方法。 二:实验…

Java反序列化-RMI流程分析

RMI 在反序列化里漏洞里面是很常用的,它是一个分布式的思想。 RMI概述 RMI 通常包含两个独立的程序,一个服务端 和 一个客户端。服务端通过绑定这个远程对象类,它可以封装网络操作。客户端层面上只需要传递一个名字,还有地址。 …

LNMP 环境下使用 Zstd 压缩优化网站备份脚本

网站的备份一直都是网站运营、服务器运维中很重要的一环,明月无论是在自己的服务器还是客户的代运维服务器上都是非常重视网站备份的,尤其热衷于优化网站备份这块儿,毕竟明月自己的服务器配置一直都是最低的 1H1G 呀,就这配置常年…

(函数)空格填充(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//声明空格填充函数&#xff1b; void space(char a[100]);int main() {//初始化变量值&#xff1b;char a[100] { 0 };//获取用户输入的数据&#xff1b;print…

人工智能学习笔记(1):了解sklearn

sklearn 简介 Sklearn是一个基于Python语言的开源机器学习库。全称Scikit-Learn&#xff0c;是建立在诸如NumPy、SciPy和matplotlib等其他Python库之上&#xff0c;为用户提供了一系列高质量的机器学习算法&#xff0c;其典型特点有&#xff1a; 简单有效的工具进行预测数据分…

Kafka生产者消息异步发送并返回发送信息api编写教程

1.引入依赖&#xff08;pox.xml文件&#xff09; <dependencies> <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>3.6.2</version> </dependency> </depende…

泰中完成潜艇采购谈判:有三个亮点值得关注

泰中完成潜艇采购谈判&#xff1a;有三个亮点值得关注 --如何写好产品采购制造类合同&#xff08;或协议&#xff09;才能有效维护你的利益 据新华网消息&#xff1a;泰国和中国已经完成关于泰国皇家海军购买中国制造的S26T元级潜艇的谈判。这份交易正在等待内阁的最终批准。…

WALT算法简介

WALT(Windows-Assist Load Tracing)算法是由Qcom开发&#xff0c; 通过把时间划分为窗口&#xff0c;对 task运行时间和CPU负载进行跟踪计算的方法。为任务调度、迁移、负载均衡及CPU调频 提供输入。 WALT相对PELT算法&#xff0c;更能及时反映负载变化&#xff0c; 更适用于…

黄金期货与现货黄金有什么区别?

如今&#xff0c;黄金成为了众多投资者的热门选择。在黄金投资市场中&#xff0c;有多种形式可供选择&#xff0c;比如纸黄金、实物黄金、黄金期货以及现货黄金等。其中&#xff0c;纸黄金和实物黄金虽然具有其特点&#xff0c;但所需资金量较大且收益表现相对不明显。相对而言…

哈希重要思想续——布隆过滤器

布隆过滤器 一 概念1.1布隆过滤器的提出2.概念 二 模拟实现2.1 三个仿函数setTest 全代码三 实际应用 一 概念 1.1布隆过滤器的提出 我们在使用新闻客户端看新闻时&#xff0c;它会给我们不停地推荐新的内容&#xff0c;它每次推荐时要去重&#xff0c;去掉那些已经看过的内容…

Java面试八股之守护线程和普通线程的区别

守护线程和普通线程的区别 生命周期差异&#xff1a; 普通线程&#xff08;也称为用户线程&#xff09;&#xff1a;这类线程的生命周期与程序的生命周期独立。它们会一直运行直到完成自己的任务或主动结束&#xff0c;如果一个程序中只剩下普通线程在运行&#xff0c;即使主…