【Java】Offer快到碗里来—ThreadLocal面试知识点一文搞定

Offer快到碗里来—ThreadLocal面试知识点一文搞定

大黄奔跑发布于 35 分钟前

写在之前

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 >面试官:</span>大黄同学是吧,先做个自我介绍吧

<span >大黄:</span>面试官您好,我叫大黄......

<span >面试官:</span>平时工作中,有用过ThreadLocal吗?能简单说说ThreadLocal有啥作用吗?

<span >大黄:</span>之前对这块有一些了解,ThreadLocal用于提供线程局部变量。这些变量与正常的变量不同,解决了基于线程维度的变量定义,每个线程访问一个独立初始化的变量副本(通过它的get()、set()或者remove())。

<span >面试官:</span>平时有没有了解过ThreadLocal底层是如何实现的?

<span >大黄:</span> Jdk底层内部类定义hash mapThreadLocalMap,用于用于存储线程本地变量。
ThreadLocalMap本身就是一个hash Map,其中的key为线程的Id、valueEntry对象值,其底层的数据结构同样是个数组,初始的大小为16。而ThreadLocalMapvalue是内部定义的静态内部类EntryEntry继承于WeakReference

  • 为了帮助处理大量的及长时间存活的引用对象,其内部的类Entry继承于WeakReference,主要是便于垃圾回收。

<span >面试官:</span>初始大小为16,那什么时候会扩容,如何扩容呢?

<span >大黄:</span> 当前容量达到总容量的2/3时会开始扩容,比如初始大小为16,当数组中元素个数到达12个的时候开始扩容。扩容的流程大致可以概括为:把原数组扩容2倍,并把老数组中的数据重新哈希散列进新数组中,如果发生hash冲突,则往后继续寻找空位置元素。

【Java】Offer快到碗里来—ThreadLocal面试知识点一文搞定

<span >面试官:</span>如果遇到了hash冲突,threadLocal如何解决的呢?

<span >大黄:</span> ThreadLocalMap解决Hash冲突的方式并非链表的方式,而是采用线性探测的方式

注意哦,这里解决哈希冲突的方式与hashMap处理思路不一样。

<span >面试官:</span>那你了解threadLocal的初始化流程吗,何时会被初始化呢?

<span >大黄:</span> 当用户第一次调用get()方法的时候会初始化值。

这里可以看一下源码的解释。

// 使用者需要自己实现初始化方法

protected T initialValue() {

return null;

}

<span >面试官:</span> ThreadLocal有什么缺点吗?

<span >大黄:</span> 使用ThreadLocal会发生内存泄露问题。threadlocal底层依赖的threadlocalMap中的key使用的是ThreadLocal-Entry弱引用,在没有其他地方对ThreadlocalMap-Entry依赖,key就会被回收掉,但是对应的value不会被回收掉,keynull,但是value不为null,这样没有任何的对象在使用value,Gc不会回收该对象,这就造成了内存泄露。

<span >面试官:</span> 那有什么办法可以避免内存泄露问题吗

<span >大黄:</span> 底层实现中已经考虑了这种情况,在调用 set()、get()、remove() 方法的时候,会清理掉 keynull 的记录。因此使⽤完ThreadLocal⽅法后,最好⼿动调⽤ remove() ⽅法。

<span >面试官:</span> 看你对这个还挺了解,工作中哪儿有用到吗?

<span >大黄:</span> 我们项目中的用户登录信息校验就是通过ThreadLocal实现的,在ThreadLocal的初始化方法中,去第三方服务方平台校验用户登录信息,并且将解析到的用户登录信息放到ThreadLocal包裹的用户信息中,这样即可以避免频繁调用第三方用户获取用户信息、又可以避免线程。

<span >面试官:</span> 嗯嗯,那我们继续看看......

面试未完待续........

总结

本意是想着更可能回答的十全十美,无奈知识有限,难免会有纰漏,如果你发现了错误的地方,可以加我的微信交流。(微信公众号没有留言。微信号:X1032838190

后续应该还会继续补充一篇关于《深入理解ThreadLocal源码》,给大家一起分享ThreadLocal的源码。

番外

另外,关注大黄奔跑公众号,第一时间收获独家整理的面试实战记录及面试知识点总结。

我是大黄,一个只会写HelloWorld的程序员,咱们下期见。

【Java】Offer快到碗里来—ThreadLocal面试知识点一文搞定

java后端

阅读 27发布于 35 分钟前

本作品系原创,采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议

avatar

大黄奔跑

1 声望

0 粉丝

0 条评论

得票时间

avatar

大黄奔跑

1 声望

0 粉丝

宣传栏

写在之前

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 >面试官:</span>大黄同学是吧,先做个自我介绍吧

<span >大黄:</span>面试官您好,我叫大黄......

<span >面试官:</span>平时工作中,有用过ThreadLocal吗?能简单说说ThreadLocal有啥作用吗?

<span >大黄:</span>之前对这块有一些了解,ThreadLocal用于提供线程局部变量。这些变量与正常的变量不同,解决了基于线程维度的变量定义,每个线程访问一个独立初始化的变量副本(通过它的get()、set()或者remove())。

<span >面试官:</span>平时有没有了解过ThreadLocal底层是如何实现的?

<span >大黄:</span> Jdk底层内部类定义hash mapThreadLocalMap,用于用于存储线程本地变量。
ThreadLocalMap本身就是一个hash Map,其中的key为线程的Id、valueEntry对象值,其底层的数据结构同样是个数组,初始的大小为16。而ThreadLocalMapvalue是内部定义的静态内部类EntryEntry继承于WeakReference

  • 为了帮助处理大量的及长时间存活的引用对象,其内部的类Entry继承于WeakReference,主要是便于垃圾回收。

<span >面试官:</span>初始大小为16,那什么时候会扩容,如何扩容呢?

<span >大黄:</span> 当前容量达到总容量的2/3时会开始扩容,比如初始大小为16,当数组中元素个数到达12个的时候开始扩容。扩容的流程大致可以概括为:把原数组扩容2倍,并把老数组中的数据重新哈希散列进新数组中,如果发生hash冲突,则往后继续寻找空位置元素。

【Java】Offer快到碗里来—ThreadLocal面试知识点一文搞定

<span >面试官:</span>如果遇到了hash冲突,threadLocal如何解决的呢?

<span >大黄:</span> ThreadLocalMap解决Hash冲突的方式并非链表的方式,而是采用线性探测的方式

注意哦,这里解决哈希冲突的方式与hashMap处理思路不一样。

<span >面试官:</span>那你了解threadLocal的初始化流程吗,何时会被初始化呢?

<span >大黄:</span> 当用户第一次调用get()方法的时候会初始化值。

这里可以看一下源码的解释。

// 使用者需要自己实现初始化方法

protected T initialValue() {

return null;

}

<span >面试官:</span> ThreadLocal有什么缺点吗?

<span >大黄:</span> 使用ThreadLocal会发生内存泄露问题。threadlocal底层依赖的threadlocalMap中的key使用的是ThreadLocal-Entry弱引用,在没有其他地方对ThreadlocalMap-Entry依赖,key就会被回收掉,但是对应的value不会被回收掉,keynull,但是value不为null,这样没有任何的对象在使用value,Gc不会回收该对象,这就造成了内存泄露。

<span >面试官:</span> 那有什么办法可以避免内存泄露问题吗

<span >大黄:</span> 底层实现中已经考虑了这种情况,在调用 set()、get()、remove() 方法的时候,会清理掉 keynull 的记录。因此使⽤完ThreadLocal⽅法后,最好⼿动调⽤ remove() ⽅法。

<span >面试官:</span> 看你对这个还挺了解,工作中哪儿有用到吗?

<span >大黄:</span> 我们项目中的用户登录信息校验就是通过ThreadLocal实现的,在ThreadLocal的初始化方法中,去第三方服务方平台校验用户登录信息,并且将解析到的用户登录信息放到ThreadLocal包裹的用户信息中,这样即可以避免频繁调用第三方用户获取用户信息、又可以避免线程。

<span >面试官:</span> 嗯嗯,那我们继续看看......

面试未完待续........

总结

本意是想着更可能回答的十全十美,无奈知识有限,难免会有纰漏,如果你发现了错误的地方,可以加我的微信交流。(微信公众号没有留言。微信号:X1032838190

后续应该还会继续补充一篇关于《深入理解ThreadLocal源码》,给大家一起分享ThreadLocal的源码。

番外

另外,关注大黄奔跑公众号,第一时间收获独家整理的面试实战记录及面试知识点总结。

我是大黄,一个只会写HelloWorld的程序员,咱们下期见。

【Java】Offer快到碗里来—ThreadLocal面试知识点一文搞定

以上是 【Java】Offer快到碗里来—ThreadLocal面试知识点一文搞定 的全部内容, 来源链接: utcz.com/a/107061.html

回到顶部