首页
题库
公司真题
专项练习
面试题库
在线编程
面试
面试经验
AI 模拟面试
简历
求职
学习
基础学习课
实战项目课
求职辅导课
专栏&文章
竞赛
我要招人
发布职位
发布职位、邀约牛人
更多企业解决方案
AI面试、笔试、校招、雇品
HR免费试用AI面试
最新面试提效必备
登录
/
注册
luke003
门头沟学院 Java
发布于辽宁
关注
已关注
取消关注
@牛客276278959号:
threadlocal个人理解
0.threadlocal的应用场景?1.存放数据的容器底层的数据结构是什么样的?2.为什么会内存泄露?3.为什么会设计成两个引用指向同一个threadlocal对象?4.软引用 优化了什么问题?5.创建一个threadlocal对象为何使用static修饰,有哪些本质原因?6.为什么必须通过finally块去调用remove方法清理对象?7.扩容机制带来的内存泄露?0A:A方法调用B方法,B方法调用C方法,如果想要传值,可以通过方法传参或者包装的对象属性进行传参,那如果这个调用链路很长呢?A->B->C->....->Z方法,但是我们发现程序的执行流顺序是自上而下的,那如果我在A点把值存到当前线程上,再在Z方法把值从当前线程上取出来用,那就不需要通过传参的方式去传,因此在 一些框架上通常可以看到XXXContext,其实就是应用了threadlocal。1A:问题0上说明了我们要把值存在线程类里,那在线程类里就会有一个容器,因为线程里面有可能会放很多值嘛,这个容器就是一个ThreadLocalMap,它的底层是一个Entry[],Entry里有两个属性,Key和Value,Value是存的值,Key是当前的threadlocal对象且弱引用指向,key这么去设计问题3会具体说明,虽然ThreadLocalMap也叫map,但是和HashMap在数据结构是有本质区别,ThreadLocalMap仅仅只有一个数组,出现hash冲突不会像HashMap还能添加链表节点或者树节点,ThreadLocalMap没有这些概念,ThreadLocal是使用了线性探测法去找自己的位置,寻址算法是,先去通过key的hash值去计算出数组中的一个位置,如果这个位置没有Entry节点,自己占了,如果有Entry节点,从当前位置往后探测,探测到没有Entry节点占用位置为止,那如果探测到数组的最大下标位置时怎么办,会重新回到下标0位置继续探测,所以 Entry数组,可以理解是一个“数组环”,当然了,在探测过程中有可能遇到一些Entry节点的key部分为null的节点,遇到这种情况呢,会进入这个下标,往前探到null,往后探到null,中间的区域会将key部分为null的节点清理掉,并会将这个区域里的正常节点rehash,那至于为什么会出现key部分为null的节点,其实是和问题4,5有关的。因此,ThreadLocal的哈希冲突有可能确实是计算的位置都一样,也有可能别的Entry节点的位置也被占了,线性探测到当前这个Entry节点上的。2A:由于java线程的特殊性,java线程就是CPU线程的映射,创建线程,销毁线程都存在内核用户态的切换,而且开启一个线程就需要分配栈内存,大量创建有可能造成内存的溢出,因此都是通过线程池去缓存线程,那可以认为这些线程都属于gc root下的对象,难以被回收,因此ThreadLocalMap里的对象都是难以被回收,gc root根可达性算法这个不需要多说吧,因此造成内存泄露。3A:首先上面知道为什么要把值存到线程里了,并且知道存在的容器其实就是一个数组,那么问题来了,Thread类属于一个很重要的类,会给你直接开放取值存值的方法吗,如果这样设计,你还需要不停的去调用Thread.currentThread(),在去通过这个线程去调用取值存值的方法,还需要去在Thread类应对数组的扩容问题,那这个从解耦的角度上讲,是不是就不行,Thread类里面只给你提供一个容器,那至于容器里面存取值或者扩容,我们写一个类给你,并且优雅的给你提供一些解决内存泄露的机制和方法。因此ThreadLocal其实就是一个操作当前线程ThreadLocalMap的门户或者是API。那现在门户有了,该来聊聊存取值的规则了,一个线程容器里面可以存多个值,那该如何区分呢,之前说过嘛,就是Entry节点的key,使用的就是当前ThreadLocal对象,那为什么会采用这样的设计,而不是采用类似于HashMap的设计,那如果采用HashMap的设计,我估计是这样的写法:threadlocal.set(Key, "value"),Key是个Object类型,这个设计思路要求Key这个值在A->B->C->....->Z的调用链路上要做到可见性,最好做成static对象并且还要维护起来,如果真这么玩的话,Threadlocal就肯定做成单例的了。但是你发现本身ThreadLocal这个API入口的对象在调用链路上本身就具有可见性,那干脆直接以自己为key,那就是现在的写法threadlocal.set("value"),因此要想多存几个值,你就需要多个ThreadLocal对象,因此ThreadLocal对象是多例的。当然了,很多人就得反驳了,就单单是这一点好处显然站不住脚,这只是原因1,原因2,得从问题4上去寻找答案。4A:从问题3可以得出,有两个引用指向了同一个ThreadLcoal对象,外面是个强引用,里面key部分是个弱引用。那为什么设计成弱引用,假设现在有个场景,我通过ThreadLocal将值放入线程容器里面,在还没有清理值之前,突然访问线程容器的门户消失了,因为你不可能null.remove()吧,也有人说为什么会出现这种情况,比方说外面强引用挂载的那个对象被gc回收了,是不是就会出现外面的强引用消失,那现在有且仅有一个弱引用指向这个ThreadLocal对象,这种情况下在下一次gc收集时就会把这个ThreadLocal对象清掉,这个时候Entry节点的key部分会“快速”反应为null,这样会有一个好处,等这个线程重新被其他业务请求拿到,框架层面或者业务本身层面使用到ThreadLocal时,做线性探测找自身Entry节点位置时,探测过程中key==null为条件,发现这类Entry节点时,会帮你清理,但是不要过于依赖这套优化机制,比如说人家一下子就找到自己的位置,没有进行探测,也没触发扩容(扩容会做一次全局清理),因此软引用只是针对外面强引用在手动清理值之前突然消失处理的一套优化机制。由此可以得出Entry数组里面的节点key部分为null的就是有问题的,那key部分不为null就没有问题吗,这个问题要带入到 问题6里面去回答。5A:其实这个问题隐隐约约在问题3里面已经回答了,因为本身ThreadLocal在调用链路上是具有可见性的,所以做成静态变量是非常方便调用链路上的方法引入使用的,当然这只是原因其中之一,还有一个原因就是static变量是gc root下的一个分支,这就保证了ThreadLocal对象难以被回收,那问题来了,这种情况下问题4中key为null还会出现吗,答案是不会,ThreadLocal对象一直在堆内存中,所以当你使用了static去做修饰,清理的代码永远不会走到,软引用的优化仅仅是针对外面强引用在手动清理值之前突然消失。6A:问题5说过当我们static修饰后,保证了ThreadLocal不会被回收,还记得问题4最后说的问题吗,key部分不为null就保证一定不是泄露对象吗?很显然不一定,如果我们没有手动清除,更为准确的说是不在finally块里面调用remove方法清理对象,都有可能产生内存泄露问题,你只set值,不remove或者不在finally块调用remove,之前抛出异常了。这两种情况都会产生内存泄露而且没有办法解决,因为ThreadLocal不会被回收,不能依靠软引用机制去清理了,此时内存泄露对象和非内存泄露对象key部分都是非null,泄露对象和正常的对象“如出一辙”,因此在内部机制是没有办法解决的,这也是为什么官方必须提供一个remove方法让大家强制调用,所以在使用ThreadLocal过程中,在一次请求的生命周期内,必须要做到用完就清理的好习惯!7A:从问题1可以了解Entry容器是一个数组,但是为什么设计成数组而不是一个链表,众所周知,数组的唯一优势就是可以从下标索引直接访问,劣势就是会占用连续的内存,如果是设计成链表,定位位置会随着链表的长度导致迭代的复杂度增加,好处就是不需要连续的内存,可以利用链表的特性形成真正的“数组环”。很显然,官方选择了数组,虽然定位很快(存在探测有可能效率降低),但是内存问题也会随之而来,令人忽视。假设现在有n个ThreadLocal,分别set一次和remove一次,操作次数总数就是2n,情景1:前n次都是set,后n次都是remove;情景2:n次set和n次remove交叉进行。请问对于我们使用ThreadLocal更希望趋向哪一种情景,很显然是情景2,因为情景1前面都是在set,有可能会将Entry数组不停的去扩容,导致分配了很多内存,且后面全部都remove了,然后一直占用这块内存,因为Entry数组是不存在缩容的。因此,得出两个结论,结论1:前n次,set次数越多,remove次数越少,就说明扩容次数越多,有可能会导致数组内存的浪费。结论2:采用二分法观察,每次分出来的次数块中的set次数和remove次数持平,可以继续做二分,因此二分的次数越多,说明扩容次数越少,内存越节省。其实可以通过生活中的例子对这类现象做类比,例如高铁,高铁的每一个站都有人上有人下,所以它的容量可以保持一个恒态,容量不会太高,如果像情景1一样,在第1站就有大批人上,请问是否需要加车厢去扩容,扩容之后等到了第2站,所以人全部下车,假设中途没人上车了,是不是就造成了资源浪费了。因此对于这个问题,官方其实也没有做出任何的解决方案,只能让我们使用大量ThreadLocal的去向场景2的趋势接近。
点赞 2
评论 0
全部评论
推荐
最新
楼层
暂无评论,快来抢首评~
相关推荐
10-29 20:30
合肥工业大学宣城校区 前端工程师
秋招前端 得物 2面 面经
9.4 时长30mins自我介绍其他offer情况讲讲实习重要的产出如果有一个相对比较成熟的网站,检测出性能缺陷,需要做首屏的性能优化,有哪些步骤或动作是可以去做的(从业务或者从代码层面上有什么方式去做优化吗)实习学到了哪些东西?感觉什么方向的提升是最大的?如何推广自己的技术方案,以及提高他人接入的积极性自己做过技术分享吗最新了解到的前端知识你觉得 react 会放弃虚拟dom吗,为什么反问
查看9道真题和解析
点赞
评论
收藏
分享
10-29 23:06
门头沟学院 前端工程师
小红书秋招前端一面 (挑战全网最快秒挂时间,还没面完就把我挂了?)
19.00-20.30面试,结果下来一看20.00发给我一个面试反馈?挑战史上最快秒挂时间,面试结束后-30min挂?自我介绍学前端的学习路径文件的并发上传,切片上传和断点续传如何实现事件循环的代码输出题,要求区分同步任务,宏任务和微任务手撕:实现最大并发请求虚拟列表的实现原理是什么?如何防止滚动时候的抖动?Vue2组件迁移到Vue3的需求背景是什么?迁移时应该注意什么问题?埋点上报做了哪些工作?自动上报怎么实现?封装了JSB通信具体是怎么实现的?页面之间的通信具体封装了哪些逻辑?除了这些还有吗?(没有,有我都说完了。。)Vite bundle analyzer具体是怎么工作的?怎么判断哪些依...
奔放的小鲸鱼想当of...:
为什么会觉得发了反馈就挂,xhs每一轮面完都会发反馈
查看29道真题和解析
点赞
评论
收藏
分享
09-30 15:18
腾讯_项目经理(实习员工)
关于多益网络!!我有话说
说实话,我无话可说
karis_aqa:
和hr没关系,都是打工的
点赞
评论
收藏
分享
09-12 15:51
南京技师学院 大堂经理
字节一年人间三年
身边去字节的朋友没有一个不说字节累的我的hxd秋招offer打牌,拿了蚂蚁转正,最后还是去了字节基本每天十点半样子下班现在经常懊悔当初就应该留在蚂蚁躺平
码农索隆:
主要钱也多啊,我钱不多啊
投递蚂蚁集团等公司10个岗位
点赞
评论
收藏
分享
11-01 12:09
门头沟学院 Java
金山办公HR面
你大概是在什么时间节点开始关注秋招岗位的?找工作的要求和期望是怎样的?有对比过其他岗位方向吗,比如前端、算法或者客户端相关之类的?你的服务端学习路径是怎样的?你一般通过哪些维度来判断是否要进入一家企业实习,即如何选择实习岗位?你的某家实习公司主要开展什么业务?哪一家企业的实习安排和工作节奏让你更适应?你如何平衡实习、课程学习以及专利、论文发表等事务?你是怎样平衡社团、比赛和编程类挑战这几者之间的关系的?在做服务端开发项目的过程中,你对自己在开发层面一般有怎样的要求?你算是学校里比较“卷”的同学吗?对于后面的技术发展方向,你更希望进行技术深耕,还是往团队管理或项目全盘管理方向发展?在技术开发过程...
查看15道真题和解析
点赞
评论
收藏
分享
评论
点赞成功,聊一聊 >
点赞
收藏
分享
评论
提到的真题
返回内容
全站热榜
更多
1
...
java后端学习经验分享(大三进大厂版)
1.4W
2
...
26届0实习秋招总结
1.0W
京东秋招开奖
热聊中
3
...
企鹅后端日常实习一面
6294
4
...
摸爬滚打,我也一定要离开华为
4196
5
...
大家秋招压力很大一般怎么调节呀
3778
6
...
26届双非本拿下美团SSP的真实感受
3710
7
...
十一月,希望有个好的开始
3554
8
...
那个绩点倒数,挂科7门的女生最后考上了985研究生
3422
9
...
愿大家都能成为很厉害的人
2819
10
...
饿了么被淘宝闪购夺舍了,HC和团队会变吗
2443
创作者周榜
更多
正在热议
更多
#
你实习是赚钱了还是亏钱了?
#
6332次浏览
55人参与
#
找工作八股要背到什么程度?
#
4871次浏览
88人参与
#
京东开奖
#
434126次浏览
2460人参与
#
秋招开始捡漏了吗
#
35546次浏览
247人参与
#
我在牛爱网找对象
#
203145次浏览
1412人参与
#
用一句话形容你的团队氛围
#
3982次浏览
50人参与
#
入职以后才知道的校招谎言
#
102246次浏览
647人参与
#
你找工作是从容有余 or 匆忙滚爬?
#
3665次浏览
44人参与
#
上班后,才发现大学__白学了
#
6262次浏览
40人参与
#
同bg的你秋招战况如何?
#
161437次浏览
935人参与
#
今年秋招还有金九银十吗
#
26373次浏览
239人参与
#
今年秋招是回暖还是遇冷
#
3903次浏览
30人参与
#
五一之后,实习真的很难找吗?
#
90489次浏览
561人参与
#
规定下班时间vs实际下班时间
#
57340次浏览
332人参与
#
学历对求职的影响
#
552961次浏览
3924人参与
#
辞职后的日常
#
16982次浏览
84人参与
#
你喜欢工作还是上学
#
79634次浏览
865人参与
#
打工人的精神状态
#
104008次浏览
1321人参与
#
Offer比较,求稳定还是求发展
#
65670次浏览
272人参与
#
分享一个让你热爱工作的瞬间
#
44757次浏览
395人参与
#
一人一个landing小技巧
#
129213次浏览
1467人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务