共计 4011 个字符,预计需要花费 11 分钟才能阅读完成。
微信公众号:大黄奔跑
关注我,可理解更多乏味的面试相干问题。
写在之前
Hello,大家好,第一次周末发文,明天持续给大家带来《Offer 到碗里来》系列的第五篇——一个问题,引发的 ThreadLocal
一系列思考。
为啥忽然想以 ThreadLocal
为主题写一篇文章呢?最近组里来了很多新同学,对于我的项目中 ThreadLocal 的局部用利用不太了解,问的人多了,因而利用平时工夫对于 ThreadLocal
面试题,外围源码梳理,一则便于本人了解,二来分享给大家用于独特交换。
对于 ThreadLocal
的原理理解的人绝对较少,并且因为应用场景无限,因而对于如何应用很多人可能也知之甚少。因而 ThreadLocal
同样会分为两个专题,面试、源码两个角度剖析。
依照常规,咱们先来看看面试中会如何考查 ThreadLocal
呢?
ThreadLocal 常见面试问题
- ThreadLocal 是什么?“ 为什么用
ThreadLocal
?”,ThreadLocal
能解决什么问题? ThreadLocal
的原理【字节跳动】ThreadLocal
何时会被初始化【美团】ThreadLocal
底层构造【美团】threadlocal
底层原理,怎么解决hash
抵触的【百度】ThreadLocal
如何应用,ThreadLocal
会产生 内存泄露 的起因【腾讯】- threadlocal的实现,原理,业务用来做什么?
- 那
ThreadLocal
须要加锁吗? - 平时工作用
ThreadLocal
的场景
………
能够看到 ThreadLocal
能够被问到的问题泛滥,然而认真发现大类次要有,ThreadLocal
是什么,有什么作用,底层原理、底层的数据结构、初始化的流程、内存泄露起因 ….
面试场景模仿
叮铃叮铃 …. 一个相熟的电话响起,对面传来饱经沧桑的声音,一听就是刚熬夜解 bug
的大哥。
<span style=”color: #5bdaed; font-size:1.2em; “> 面试官:</span> 大黄同学是吧,先做个自我介绍吧
<span style=”color: #5bdaed; font-size:1.2em; “> 大黄:</span> 面试官您好,我叫大黄 ……
<span style=”color: #5bdaed; font-size:1.2em; “> 面试官:</span> 平时工作中,有用过 ThreadLocal
吗?能简略说说 ThreadLocal
有啥作用吗?
<span style=”color: #5bdaed; font-size:1.2em; “> 大黄:</span> 之前对这块有一些理解,ThreadLocal
用于提供线程局部变量。这些变量与失常的变量不同,解决了基于线程维度的变量定义,每个线程拜访一个独立初始化的变量正本 (通过它的 get()、set() 或者 remove())。
大黄小揭示
ThreadLocal 创立的目标不是为了解决多线程问题,因为各个变量都在本人的线程中,不存在变量共享、也就不存在竞争了,所以自身也就是线程平安的。
<span style=”color: #5bdaed; font-size:1.2em; “> 面试官:</span> 平时有没有理解过 ThreadLocal
底层是如何实现的?
<span style=”color: #5bdaed; font-size:1.2em; “> 大黄:</span> Jdk
底层外部类定义 hash map
的ThreadLocalMap
,用于用于存储线程本地变量。ThreadLocalMap
自身就是一个 hash Map,其中的 key
为线程的 Id、value
为 Entry
对象值,其底层的数据结构同样是个数组,初始的大小为 16。而 ThreadLocalMap
的value
是外部定义的动态外部类 Entry
,Entry
继承于WeakReference
大黄小揭示
Entry
为什么要继承于WeakReference
呢?
- 为了帮忙解决大量的及长时间存活的援用对象,其外部的类
Entry
继承于WeakReference
,次要是便于垃圾回收。
WeakReference
作用是:利用弱援用时,过期的对象只有在内存空间有余的时候,垃圾回收器就会回收该对象。
<span style=”color: #5bdaed; font-size:1.2em; “> 面试官:</span> 初始大小为 16,那什么时候会扩容,如何扩容呢?
<span style=”color: #5bdaed; font-size:1.2em; “> 大黄:</span> 以后容量达到总容量的 2 / 3 时会开始扩容,比方初始大小为 16,当数组中元素个数达到 12 个的时候开始扩容。扩容的流程大抵能够概括为:把原数组扩容 2 倍,并把老数组中的数据从新哈希散列进新数组中,如果产生 hash 抵触,则往后持续寻找空地位元素。
如果面试官持续问扩容思路,能够参考下图,联合源码一起了解。
<span style=”color: #5bdaed; font-size:1.2em; “> 面试官:</span> 如果遇到了 hash
抵触,threadLocal
如何解决的呢?
<span style=”color: #5bdaed; font-size:1.2em; “> 大黄:</span> ThreadLocalMap
解决 Hash
抵触的形式并非链表的形式,而是采纳线性探测的形式
大黄小课堂
线性探测:依据初始key
的hashcode
值确定元素在table
数组中的地位,如果发现这个地位上曾经有其余 key 值的元素被占用,则利用固定的算法寻找肯定步长的下个地位,顺次判断,直至找到可能寄存的地位。
留神哦,这里解决哈希抵触的形式与 hashMap 解决思路不一样。
<span style=”color: #5bdaed; font-size:1.2em; “> 面试官:</span> 那你理解 threadLocal 的初始化流程吗,何时会被初始化呢?
<span style=”color: #5bdaed; font-size:1.2em; “> 大黄:</span> 当用户第一次调用 get()
办法的时候会初始化值。
这里能够看一下源码的解释。
设置以后线程 thread-local 变量的初始值。
在调用 get()办法时,如果使用者重写了 initialValue()办法,则用重写的逻辑初始化,否则会主动调用 set()办法,进行值的初始化,
失常状况下,该办法最多会被调用一次,然而如果在 get()之后调用了 remove()办法移除元素,则该办法可能被调用第二次。
办法默认返回 null,如果使用者想要返回的非空值,则须要继承{@code ThreadLocal},子类去重写该办法。
// 使用者须要本人实现初始化办法
protected T initialValue() {return null;}
<span style=”color: #5bdaed; font-size:1.2em; “> 面试官:</span> ThreadLocal 有什么毛病吗?
记住,这里面试官大略是想问
ThreadLocal
的内存泄露问题
<span style=”color: #5bdaed; font-size:1.2em; “> 大黄:</span> 应用 ThreadLocal
会产生内存泄露问题。threadlocal
底层依赖的 threadlocalMap
中的 key
应用的是 ThreadLocal-Entry
弱援用,在没有其余中央对 ThreadlocalMap-Entry
依赖,key
就会被回收掉,然而对应的 value
不会被回收掉,key
为 null
,然而value
不为null
,这样没有任何的对象在应用 value,Gc 不会回收该对象,这就造成了内存泄露。
<span style=”color: #5bdaed; font-size:1.2em; “> 面试官:</span> 那有什么方法能够防止内存泄露问题吗
<span style=”color: #5bdaed; font-size:1.2em; “> 大黄:</span> 底层实现中曾经思考了这种状况,在调用 set()、get()、remove()
办法的时候,会清理掉 key
为 null
的记录。因而使⽤完 ThreadLocal
⽅法后,最好⼿动调⽤ remove()
⽅法。
内存泄露,只有在呈现了 key 为 null 的记录后,没有手动调用 remove() 办法,并且之后也不再调用 get()、set()、remove() 办法的状况下。
<span style=”color: #5bdaed; font-size:1.2em; “> 面试官:</span> 看你对这个还挺理解,工作中哪儿有用到吗?
<span style=”color: #5bdaed; font-size:1.2em; “> 大黄:</span> 咱们我的项目中的用户登录信息校验就是通过 ThreadLocal
实现的,在 ThreadLocal
的初始化办法中,去第三方服务方平台校验用户登录信息,并且将解析到的用户登录信息放到 ThreadLocal
包裹的用户信息中,这样即能够防止频繁调用第三方用户获取用户信息、又能够防止线程。
<span style=”color: #5bdaed; font-size:1.2em; “> 面试官:</span> 嗯嗯,那咱们持续看看 ……
面试未完待续 ……..
当然,如果每个问题都能够答复如此,Offer 天然到碗里来。
总结
本意是想着更可能答复的美中不足,无奈常识无限,难免会有纰漏,如果你发现了谬误的中央,能够加我的微信交换。(微信公众号没有留言。微信号:X1032838190
)
后续应该还会持续补充一篇对于《深刻了解 ThreadLocal 源码》,给大家一起分享 ThreadLocal
的源码。
番外
另外,关注大黄奔跑公众号,第一工夫播种独家整顿的面试实战记录及面试知识点总结。
我是大黄,一个只会写 HelloWorld
的程序员,咱们下期见。