java面试一日一题:讲下ThreadLocal
问题:请讲下ThreadLocal
分析:首先要了解ThreadLocal的基本原理;其次要理解ThreadLocal发生内存泄漏的原因;最后ThreadLocal是如何做到线程隔离的
回答要点:
主要从以下几点去考虑,
1、ThreadLocal的基本原理
2、ThreadLocal为什么会发生内存泄漏?
3、ThreadLocal如何做到线程隔离?
ThreadLocal相当于操作线程中局部变量的一个工具类,其过程是通过操作每个线程内部的ThreadLocalMap来实现的,也就是说在每个线程内部都有一个ThreadLocalMap,该map在存储的时候使用的key为ThreadLocal,value为设置的value,其底层是一个Entry数组。 由于每个线程都有一个ThreadLocalMap,在线程A中使用ThreadLocal放入一个value,那么在线程B中使用ThreadLocal获取的时候,一定是获取不到的,因为每个线程有自己独立的ThreadLocalMap,使用ThreadLocal设置的值最终是存储在线程的ThreadLocalMap中的。
既然是一个Map的结构,就会发生冲突,在HashMap中解决hash冲突使用的是链地址法,在ThreadLocalMap中使用的是线性探测法。
重点看下ThreadLocal的几个重点方法,
get()方法
public T get() {
//获得当前线程
Thread t = Thread.currentThread();
//从当前线程中获得其ThreadLocal.ThreadLocalMap变量
ThreadLocalMap map = getMap(t);
if (map != null) {
//这里的this只得是调用该get()方法的对象,也就是一个ThreadLocal的实例,
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
上面的方法做了注释,在使用ThreadLocal的get方法时首先是获得当前调用线程的一个ThreadLocalMap,然后从该Map中获得value。
set()方法
public void set(T value) {
//获得当前线程
Thread t = Thread.currentThread();
//获得当前线程中的ThreadLocal.ThreadLocalMap对象
ThreadLocalMap map = getMap(t);
if (map != null)
//使用this(也就是ThreadLocal作为key)放入ThreadLocalMap中
map.set(this, value);
else
createMap(t, value);//新建一个ThreadLocalMap并放入值
}
从上面可以看到set方法也是要获得当前线程的ThreadLocalMap对象,然后往该对象中放value,下面看下createMap方法
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
可以看到就是给Thread的threadLocals变量赋值,赋值一个ThreadLocalMap,那么threadLocals肯定是一个ThreadLocal.ThreadLocalMap,看下该变量

通过上面的分析,已经很清晰了ThreadLocal操作的都是当前线程中的变量,和其他线程是没有关系的,所以本身就不存在线程安全的问题;
网上经常看到说ThreadLocal有内存泄漏的风险,那么内存泄漏是如何产生的?

上图,画了下get的一个过程,正常情况下是ThreadLocal.get()-->thread->threadLocalMap-Entry[]-entry(key,value)这样一个查找路径,由于Entry中的key是一个weakReference对象,也就是弱引用,在一次gc的过程中会被回收,那么这时Entry中的key就是null了,再通过上面的线路是找不到的,那么这样一个Entry对象中的value就无法再找到了,但由于value又是强引用,不会被回收,该entry对象就造成了内存泄漏,所以正确的使用方法是在使用完之后调用remove()方法。
最后有个问题,请广大网友解惑,在ThreadLocal中存储的是引用类型的情况下,是如何做到线程隔离的,望解惑,感谢!
其实如果在ThreadLocal中存储得是引用类型,也就是可变对象,那么在一个线程中对value进行改变,在其他线程中渠道的值肯定是改变后的。所以在使用中基本类型是可以随便用的,当使用到了引用类型要注意;
总结:
1、ThreadLocal不是为每个线程创建副本变量,而是由于每个线程中的threadLocals是线程独有的,其他线程无法访问;
2、谨慎的使用引用类型,因为在一个线程中对其值的改变会影响其他线程中值得变化;
3、在使用完,记得remove,防止内存泄漏得风险;

java面试一日一题:讲下ThreadLocal的更多相关文章
- java面试一日一题:讲下在什么情况下会发生类加载
问题:请讲下在什么情况下会发生类加载? 分析:该问题主要考察对java中类加载的知识,什么是类加载,为什么会发生类加载,什么情况下发生类加载? 回答要点: 主要从以下几点去考虑 1.什么是类加载: 2 ...
- java面试一日一题:讲下mysql中的undolog
问题:请讲下mysql中undo log的作用 分析:mysql中有很多日志,例,bin log undo log redo log,要弄清楚这些日志的作用,就要了解这些日志出现的背景及要解决的问题: ...
- java面试一日一题:mysql中常用的存储引擎有哪些?
问题:请讲下mysql中常用的引擎有哪些? 分析:该问题主要考察对mysql存储引擎的理解,及区别是什么? 回答要点: 主要从以下几点去考虑, 1.mysql的存储引擎的基本概念? 2.mysql中常 ...
- java面试一日一题:java中垃圾回收算法有哪些
问题:请讲下在java中有哪些垃圾回收算法 分析:该问题主要考察对java中垃圾回收的算法以及使用场景 回答要点: 主要从以下几点去考虑, 1.GC回收算法有哪些 2.每种算法的使用场景 3.基于垃圾 ...
- java面试一日一题:java中的垃圾回收器
问题:请讲下java中垃圾回收器有哪些? 分析:该问题主要考察hotspot虚拟机下实现的垃圾回收器 回答要点: 主要从以下几点去考虑, 1.垃圾回收器的种类 2.每种垃圾回收器的着重点是什么 前边的 ...
- java面试一日一题:请讲下对mysql的理解
问题:请讲下对mysql的理解 分析:该问题主要考察对mysql的理解,基本概念及sql的执行流程 回答要点: 主要从以下几点去考虑, 1.mysql的整体架构? 2.mysql中每一个组件的作用? ...
- java面试一日一题:讲下redo log
问题:请讲下redo log的作用 分析:mysql中有很多日志,例,binlog undo log redo log,要弄清楚这些日志的作用,就要了解这些日志出现的背景及要解决的问题? 回答要点: ...
- java面试一日一题:讲下mysql中的索引
问题:请讲下mysql中的索引 分析:mysql中有很多索引,要对对这些索引有所掌握,还要弄清楚每种索引的本质? 回答要点: 主要从以下几点去考虑 1.索引的本质是什么 2.mysql的索引分类: 3 ...
- java面试一日一题:讲对mysql的MVCC的理解
问题:请讲下对mysql中MVCC的理解 分析:这个问题要回答的是对MVCC的理解,以及MVCC解决了什么问题这几个方面入手. 回答要点: 主要从以下几点去考虑, 1.什么是MVCC? 2.MVCC用 ...
- java面试一日一题:java线程池
问题:请讲下java中的线程池 分析:在面试中经常问到线程池的问题,要掌握其基本概念,使用方法,注意事项等,引申下tomcat中默认的线程数是多少 回答要点: 主要从以下几点去考虑, 1.为什么要使用 ...
随机推荐
- Android 13 - Media框架(12)- MediaCodec(二)
关注公众号免费阅读全文,进入音视频开发技术分享群! 前面一节我们学习了 MediaCodec 的创建以及配置过程,了解部分设计机制以及功能,这一节我们将继续学习其他方法. 1.start start ...
- 一个 .NET 开源的地图组件库 - Mapsui
前言 今天大姚给大家分享一个.NET开源(MIT License).免费.同时支持多平台框架(MAUI.WPF.Avalonia.Uno.Blazor.WinUI.Eto..NET Android 和 ...
- sort awk 文本处理命令
sort: 1.将文件的每一行作为一个单位,相互比较 2.默认升序 3.以字符来进行对比,从首字符开始往后,依次按ASCII码值排序 sort 显示文件内容 (类似cat) 选项: -u 去掉重复行 ...
- Qt QMainWindow的使用
参考视频:黑马科技:https://www.bilibili.com/video/BV1XW411x7NU?p=19 QMainWindow是一个为用户提供主窗口程序的类,包含一个菜单栏(menu b ...
- windows 批处理 检查并启动 windows 服务
windows 批处理 检查并启动 windows 服务 set srvname="YSWindowsService" sc query|find %srvname% && ...
- 企业级私有仓库Harbor
仓库的概念也就是用于存储,docker仓库用于存储镜像. 镜像构建完成后,很容易可以在宿主机上运行,但是如果要在其他服务器上运行,则需要考虑镜像的分发,存储的问题. 共有/私有/仓库 Docker R ...
- Linux Debian安装教程
Debian 是一个免费的开源操作系统,是最古老的 Linux 发行版之一,于 1993 年由 Ian Murdock 创建.它采用了自由软件协议,并且由志愿者社区维护和支持.Debian 的目标是创 ...
- 在线RSA公私钥PKCS格式互转工具
在线公私钥PKCS格式转换,支持公钥PKCS1与PKCS8格式之间相互转换,私钥PKCS1与PKCS8格式之间相互转换:PKCS1定义RSA公开密钥算法加密和签名机制,PKCS8描述私有密钥信息格式, ...
- Vulnhub Mercy Walkthrough
Recon 首先进行二层扫描. ┌──(kali㉿kali)-[~] └─$ sudo netdiscover -r 192.168.80.0/24 Currently scanning: Finis ...
- STM32 学习:IAP有关介绍
--- title: mcu-stm32-IAP-0-about date: 2020-05-27 08:51:58 categories: tags: - iap - stm32 - about - ...