Java 200+ 面试题补充 ThreadLocal 模块
让我们每天都有进步,老王带你打造最全的 Java 面试清单,认真把一件事做到极致。
本文是前文《Java 最常见的 200+ 面试题》的第一个补充模块。
1.ThreadLocal 是什么?
ThreadLocal 是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,适用于各个线程不共享变量值的操作。
2.ThreadLocal 工作原理是什么?
ThreadLocal 原理:每个线程的内部都维护了一个 ThreadLocalMap,它是一个 Map(key,value)数据格式,key 是一个弱引用,也就是 ThreadLocal 本身,而 value 存的是线程变量的值。
也就是说 ThreadLocal 本身并不存储线程的变量值,它只是一个工具,用来维护线程内部的 Map,帮助存和取变量。
数据结构,如下图所示:
(图片来源于网络)
3.ThreadLocal 如何解决 Hash 冲突?
与 HashMap 不同,ThreadLocalMap 结构非常简单,没有 next 引用,也就是说 ThreadLocalMap 中解决 Hash 冲突的方式并非链表的方式,而是采用线性探测的方式。所谓线性探测,就是根据初始 key 的 hashcode 值确定元素在 table 数组中的位置,如果发现这个位置上已经被其他的 key 值占用,则利用固定的算法寻找一定步长的下个位置,依次判断,直至找到能够存放的位置。
源代码实现如下:
/
* Increment i modulo len.
*/
private static int nextIndex(int i, int len) {
return ((i + 1 < len) ? i + 1 : 0);
}
/
* Decrement i modulo len.
*/
private static int prevIndex(int i, int len) {
return ((i - 1 >= 0) ? i - 1 : len - 1);
}
4.ThreadLocal 的内存泄露是怎么回事?
ThreadLocal 在 ThreadLocalMap 中是以一个弱引用身份被 Entry 中的 Key 引用的,因此如果 ThreadLocal 没有外部强引用来引用它,那么 ThreadLocal 会在下次 JVM 垃圾收集时被回收。这个时候 Entry 中的 key 已经被回收,但是 value 又是一强引用不会被垃圾收集器回收,这样 ThreadLocal 的线程如果一直持续运行,value 就一直得不到回收,这样就会发生内存泄露。
5.为什么 ThreadLocalMap 的 key 是弱引用?
我们知道 ThreadLocalMap 中的 key 是弱引用,而 value 是强引用才会导致内存泄露的问题,至于为什么要这样设计,这样分为两种情况来讨论:
- key 使用强引用:这样会导致一个问题,引用的 ThreadLocal 的对象被回收了,但是 ThreadLocalMap 还持有 ThreadLocal 的强引用,如果没有手动删除,ThreadLocal 不会被回收,则会导致内存泄漏。
- key 使用弱引用:这样的话,引用的 ThreadLocal 的对象被回收了,由于 ThreadLocalMap 持有 ThreadLocal 的弱引用,即使没有手动删除,ThreadLocal 也会被回收。value 在下一次 ThreadLocalMap 调用 set、get、remove 的时候会被清除。
比较以上两种情况,我们可以发现:由于 ThreadLocalMap 的生命周期跟 Thread 一样长,如果都没有手动删除对应 key,都会导致内存泄漏,但是使用弱引用可以多一层保障,弱引用 ThreadLocal 不会内存泄漏,对应的 value 在下一次 ThreadLocalMap 调用 set、get、remove 的时候被清除,算是最优的解决方案。
6.ThreadLocal 的应用场景有哪些?
ThreadLocal 适用于独立变量副本的情况,比如 Hibernate 的 session 获取场景。
示例代码:
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
public static Session getCurrentSession(){
Session session = threadLocal.get();
try {
if(session ==null&&!session.isOpen()){
//...
}
threadLocal.set(session);
} catch (Exception e) {
// TODO: handle exception
}
return session;
}
查看所有面试题:《Java 最常见 200+ 面试题》
参考资料
https://www.jianshu.com/p/a1cd61fa22da
https://www.jianshu.com/p/98b68c97df9b
扫描下方二维码,关注更多动态:
往期文章推荐:
Java 200+ 面试题补充 ThreadLocal 模块的更多相关文章
- Java 200+ 面试题补充② Netty 模块
让我们每天都能看到自己的进步.老王带你打造最全的 Java 面试清单,认真把一件事做到最好. 本文是前文<Java 最常见的 200+ 面试题>的第二个补充模块,第一模块为:<Jav ...
- Java 200+ 面试题补充③ Dubbo 模块
昨天在我的 Java 面试粉丝群里,有一个只有一年开发经验的小伙伴只用了三天时间,就找到了一个年薪 20 万的工作,真是替他感到开心. 他的经历告诉我们:除了加强自我实战经验之外,还要努力积累自己的理 ...
- Java 208 道面试题:第一模块答案
目前市面上的面试题存在两大问题:第一,题目太旧好久没有更新了,还都停留在 2010 年之前的状态:第二,近几年 JDK 更新和发布都很快,Java 的用法也变了不少,加上 Java 技术栈也加入了很多 ...
- Java高级面试题解析(一)
最近,在看一些java高级面试题,我发现我在认真研究一个面试题的时候,我自己的收获是很大的,我们在看看面试题的时候,不仅仅要看这个问题本身,还要看这个问题的衍生问题,一个问题有些时候可能是一个问题群( ...
- Java笔试面试题整理第五波
转载至:http://blog.csdn.net/shakespeare001/article/details/51321498 作者:山代王(开心阳) 本系列整理Java相关的笔试面试知识点,其他几 ...
- 15个顶级Java多线程面试题及回答
Java 线程面试问题 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分.如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程 的问题.在投资银行业务中多线程和并发 ...
- 【转载】 Java线程面试题 Top 50
Java线程面试题 Top 50 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员 的欢迎.大多数待遇丰厚的J ...
- java常见面试题及答案 1-10(基础篇)
java常见面试题及答案 1.什么是Java虚拟机?为什么Java被称作是"平台无关的编程语言"? Java 虚拟机是一个可以执行 Java 字节码的虚拟机进程.Java 源文件被 ...
- Java线程面试题 Top 50 (转载)
转载自:http://www.cnblogs.com/dolphin0520/p/3958019.html 原文链接:http://www.importnew.com/12773.html 本文由 ...
随机推荐
- 记一个常见的ms sql server中取第N条记录的方法
前言 好好学习,天天向上. 正文 好像也是一个不难的问题,刚视频里看到的,就记一下吧. 下面是表中原始的数据结构,做了一个倒叙排序: select * from Employee order by S ...
- Leetcode 第133场周赛解题报告
今天参加了leetcode的周赛,算法比赛,要求速度比较快.有思路就立马启动,不会纠结是否有更好的方法或代码可读性.只要在算法复杂度数量级内,基本上是怎么实现快速就怎么来了. 比赛时先看的第二题,一看 ...
- Redux进阶(像VUEX一样使用Redux)
更好的阅度体验 前言 redux的问题 方案目标 如何实现 思考 前言 Redux是一个非常实用的状态管理库,对于大多数使用React库的开发者来说,Redux都是会接触到的.在使用Redux享受其带 ...
- 杭电ACM2016--数据的交换输出
数据的交换输出 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Sub ...
- [Go] golang的select多路选择功能
基于select的多路复用:1.解决如果一个channel中没有事件发过来,程序会立即阻塞,无法接收到第二个channel中的事件2.一般每一个case都代表一个通信操作,多个case会选一个能执行的 ...
- Oracle day05 索引_数据去重
索引 自动:当在表上定义一个primary key或者unique 约束条件时,oracle数据库自动创建一个对应的唯一索引. 手动:用户可以创建索引以加速查询 在一列或者多列上创建索引: creat ...
- Android Material Design控件使用(三)——CardView 卡片布局和SnackBar使用
cardview 预览图 常用属性 属性名 说明 cardBackgroundColor 设置背景颜色 cardCornerRadius 设置圆角大小 cardElevation 设置z轴的阴影 ca ...
- Python全栈开发之---装饰器
1.装饰器的形成过程 import time def func1(): print('in func1') def timer(func): def inner(): start = time.tim ...
- JavaScript 包装对象
万物皆对象 在JavaScript里,万物皆对象.但是某些对象有别于其它对象,我们可以用 typeof 来获取一个对象的类型,它总是返回一个字符串. typeof 123; // 'number' t ...
- maven 聚合
聚合很简单, 在父 pom 中写出子 pom 文件的路径即可 <name>parent Maven Webapp</name> <!-- FIXME change it ...