乐趣区

关于java:Offer快到碗里来ThreadLocal面试知识点一文搞定

微信公众号:大黄奔跑
关注我,可理解更多乏味的面试相干问题。

写在之前

Hello,大家好,第一次周末发文,明天持续给大家带来《Offer 到碗里来》系列的第五篇——一个问题,引发的 ThreadLocal 一系列思考。

为啥忽然想以 ThreadLocal 为主题写一篇文章呢?最近组里来了很多新同学,对于我的项目中 ThreadLocal 的局部用利用不太了解,问的人多了,因而利用平时工夫对于 ThreadLocal 面试题,外围源码梳理,一则便于本人了解,二来分享给大家用于独特交换。

对于 ThreadLocal 的原理理解的人绝对较少,并且因为应用场景无限,因而对于如何应用很多人可能也知之甚少。因而 ThreadLocal 同样会分为两个专题,面试、源码两个角度剖析。

依照常规,咱们先来看看面试中会如何考查 ThreadLocal 呢?

ThreadLocal 常见面试问题

  1. ThreadLocal 是什么?“ 为什么用 ThreadLocal?”,ThreadLocal 能解决什么问题?
  2. ThreadLocal的原理【字节跳动】
  3. ThreadLocal何时会被初始化【美团】
  4. ThreadLocal底层构造【美团】
  5. threadlocal底层原理,怎么解决 hash 抵触的【百度】
  6. ThreadLocal如何应用,ThreadLocal会产生 内存泄露 的起因【腾讯】
  7. threadlocal的实现,原理,业务用来做什么?
  8. ThreadLocal 须要加锁吗?
  9. 平时工作用 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 mapThreadLocalMap,用于用于存储线程本地变量。
ThreadLocalMap自身就是一个 hash Map,其中的 key 为线程的 Id、valueEntry 对象值,其底层的数据结构同样是个数组,初始的大小为 16。而 ThreadLocalMapvalue是外部定义的动态外部类 EntryEntry 继承于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 抵触的形式并非链表的形式,而是采纳线性探测的形式

大黄小课堂
线性探测:依据初始 keyhashcode值确定元素在 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 不会被回收掉,keynull,然而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() 办法的时候,会清理掉 keynull 的记录。因而使⽤完 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 的程序员,咱们下期见。

退出移动版