问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

ThreadLocal原理及使用场景

发布网友 发布时间:2024-09-27 04:25

我来回答

1个回答

热心网友 时间:2024-09-28 03:47

ThreadLocal,即线程本地变量,它旨在解决多线程并发中共享变量访问的问题。

所谓的共享变量,指的是位于堆中的实例、静态属性以及数组。这些共享数据的访问受到Java内存模型(JMM)的约束。每个线程都拥有自己的本地内存,当线程访问堆中的变量时,这些变量会被复制到线程的本地内存中。当线程修改共享变量后,会通过JMM进行管理,将修改后的值写回到主内存中。

在多线程环境下,当多个线程同时修改共享变量时,就可能出现线程安全问题,即数据不一致的问题。通常,我们会通过加锁(synchronized或Lock)的方式来解决这一问题。然而,这种方法会对性能产生较大影响。为了解决这个问题,JDK1.2中引入了ThreadLocal类,通过修饰共享变量,使每个线程都单独拥有一份共享变量,从而实现线程间的隔离。

ThreadLocal的使用场景与锁的使用场景有所不同。以下是ThreadLocal的使用及原理:

1. 使用:通常将ThreadLocal声明为一个静态字段,并初始化如下:

其中Object即为原本堆中共享变量的数据。

例如,有一个User对象需要在不同线程之间进行隔离访问,可以定义ThreadLocal如下:

常用的方法包括:

set(T value):设置线程本地变量的内容。

get():获取线程本地变量的内容。

remove():移除线程本地变量。

注意:在线程池的线程复用场景中,在线程执行完毕时一定要调用remove,避免在线程被重新放入线程池中时,本地变量的旧状态仍然被保存。

1. 原理:ThreadLocal是如何在每个线程中保存一份单独的本地变量呢?首先,我们需要了解Java中的线程。线程是一个Thread类的实例对象。一个实例对象的实例成员字段内容肯定是这个对象独有的。因此,我们可以将保存ThreadLocal线程本地变量作为一个Thread类的成员字段。这个成员字段是:

它是一个ThreadLocal中定义的Map对象,用于保存该线程中的所有本地变量。ThreadLocalMap中的Entry的定义如下:

ThreadLocalMap和Entry都在ThreadLocal中定义。

1. ThreadLocal设计:在JDK早期的设计中,每个ThreadLocal都有一个map对象,将线程作为map对象的key,要存储的变量作为map的value。然而,在JDK8之后,每个Thread维护一个ThreadLocalMap对象,这个Map的key是ThreadLocal实例本身,value是存储的值要隔离的变量,是泛型。具体过程如下:

每个Thread线程内部都有一个Map(ThreadLocalMap::threadlocals);Map里面存储ThreadLocal对象(key)和线程的变量副本(value);Thread内部的Map由ThreadLocal维护,由ThreadLocal负责向map获取和设置变量值;对于不同的线程,每次获取副本值时,别的线程不能获取当前线程的副本值,就形成了数据之间的隔离。

1. 使用ThreadLocal的好处:保存每个线程绑定的数据,在需要的地方可以直接获取,避免直接传递参数带来的代码耦合问题;各个线程之间的数据相互隔离却又具备并发性,避免同步方式带来的性能损失。

2. ThreadLocal内存泄露问题:内存泄露问题指程序中动态分配的堆内存由于某种原因没有被释放或者无法释放,造成系统内存的浪费,导致程序运行速度减慢或者系统崩溃等严重后果。内存泄露堆积将会导致内存溢出。

ThreadLocal的内存泄露问题一般考虑和Entry对象有关。在Entry定义中可以看出ThreadLocal::Entry被弱引用所修饰。JVM会将弱引用修饰的对象在下次垃圾回收中清除掉。这样就可以实现ThreadLocal的生命周期和线程的生命周期解绑。但实际上,并不是使用了弱引用就一定不会发生内存泄露问题。考虑以下几个过程:

使用强引用:当ThreadLocal Ref被回收了,由于在Entry使用的是强引用,在Current Thread还存在的情况下就存在着到达Entry的引用链,无法清除掉ThreadLocal的内容,同时Entry的value也同样会被保留;也就是说,就算使用了强引用仍然会出现内存泄露问题。

使用弱引用:当ThreadLocal Ref被回收了,由于在Entry使用的是弱引用,因此在下次垃圾回收的时候就会将ThreadLocal对象清除,这个时候Entry中的KEY=null。但是由于ThreadLocalMap中仍然存在Current Thread Ref这个强引用,因此Entry中value的值仍然无法清除。还是存在内存泄露的问题。

由此可以发现,使用ThreadLocal造成内存泄露的问题是因为:ThreadLocalMap的生命周期与Thread一致,如果不手动清除掉Entry对象的话就可能会造成内存泄露问题。因此,需要我们在每次在使用完之后需要手动的remove掉Entry对象。

那么为什么使用弱引用?避免内存泄露的两种方式:使用完ThreadLocal,调用其remove方法删除对应的Entry或者使用完ThreadLocal,当前Thread也随之运行结束。第二种方法在使用线程池技术时是不可以实现的。

所以一般都是自己手动调用remove方法,调用remove方法弱引用和强引用都不会产生内存泄露问题,使用弱引用的原因如下:

在ThreadLocalMap的set/getEntry中,会对key进行判断,如果key为null,那么value也会被设置为null,这样即使在忘记调用了remove方法,当ThreadLocal被销毁时,对应value的内容也会被清空。多一层保障!

总结:存在内存泄露的有两个地方:ThreadLocal和Entry中Value;最保险还是要注意要自己及时调用remove方法!!!

3. ThreadLocal的应用场景:场景一:在重入方法中替代参数的显式传递;场景二:全局存储用户信息;场景三:解决线程安全问题。

4. 总结:ThreadLocal更像是对其他类型变量的一层包装,通过ThreadLocal的包装使得该变量可以在线程之间隔离和当前线程全局共享。线程的隔离性和变量的线程全局共享性得益于在每个Thread类中的threadlocals字段。(从类实例对象的角度抽象的去看Java中的线程!!!)ThreadLocalMap中Entry的Key不管是否使用弱引用都有内存泄露的可能。引起内存泄露主要在于ThreadLocal对象和Entry中的Value对象,因此要确保每次使用完之后都remove掉Entry!
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
梦见陌生女人在水里生下男孩,男孩很聪明,但是陌生女人夫妇把男孩当女... oppohd通话怎么关掉 oppohd通话如何关掉 华为手机密码忘记了如何解锁? 某校高一化学研究性学习小组对日常生活中的氯气用途进行了调查,了解到... 怎样使用微软的传输助手进行文件打印? 苏氏宗祠地址在哪里? 苏圩镇苏氏宗祠 苏氏祠堂广西南宁市江南区苏氏祠堂 关于秋梅的诗句有哪些? 晃晃麻将玩法介绍 人生角色简短语录 有哪些表达人生感悟的句子 湖南中茶茶业有限公司的介绍 一文读懂ThreadLocal的原理及使用场景 BRC认证BRC认证的适用范围 BRC认证什么是BRC? BRC认证为什么需要BRC 认证?谁需要BRC 认证? 什么是BRC 认证?怎么获取呢? 有什么修改位置的软件? 燃气灶烧一会自动熄火是什么原因 煤气灶点火后几秒自动熄灭 2016年的安徽中考总分是多少? 什么是基层公务员 也是通过公务员考试走 不明白不明白 考公务员是个... 楧读音是什么意思? 为什么有的人谈恋爱好难 蓝宝石HD5670 640SP 512M GDDR5 至尊版2代技术参数 ...用HD5670 512M GDDR5至尊版要不要换电源,给点建议 蓝宝石HD5670至尊版3代需要多大的电源比较好? 蓝宝HD5670显卡简介 蓝宝石HD5670 512M 黄金版基本参数 皮卡堂我想看皮卡剧,谁复制下? 人生感悟的句子抖音最火 看淡一切善待自己心态说说 起司猫的眼睛是什么颜色 怎么看品相 湖南中茶茶业有限公司经营产品 选了物理化学政治有什么的大学 学了Python 能用来做什么? 陪读轶事 拼多多买的手机坏了怎么售后 熊脱氧胆酸简介 戒坛方是什么 12岁适合扎什么发型好看的发型怎么扎? 戒法的解释 对于一个喜欢自己并且自己也有好感的男生想使彼此的关系更进一步应该怎 ... 在面对一个喜欢自己的男生,而且自己也对他有好感时,但双方都没有表明... 平山有哪些旅游景点 天桂山有哪些适合摄影爱好者的景点? 凯里旅游住哪里方便_凯里周边哪里风景好拍照 2024物化地最吃香的专业 哪些专业可以报考 物理化学地理可报专业有哪些 组合怎么样 怎么制作茄子做的素馅儿 余额宝不能转出的钱怎么消费