当前位置: 首页 > news >正文

应届生投腾讯,被面试官问了8个和 ThreadLocal 相关的问题。

问:谈一谈ThreadLocal的结构。

ThreadLocal内部维护了一个ThreadLocalMap静态内部类,ThreadLocalMap中又维护了一个Entry静态内部类,和Entry数组。

Entry类继承弱引用类WeakReference,Entry类有一个有参构造函数,参数为ThreadLocal和value值,构造方法函数内部会调用父类有参构造函数,ThreadLocal作为父类有参构造函数的参数。

其底层数据结构可以看成是一个hash表,索引是通过原子类AtomicInteger、HASH_INCREMENT( = 0x61c88647)和Entry[ ]的长度而来。

索引 = ThreadLocal#nextHashCode & (Entry[]#length - 1)nextHashCode = AtomicInteger#getAndAdd(HASH_INCREMENT)

问:你知道ThreadLocal是如何保证线程隔离的么?

在Thread内部,维护了ThreadLocal.ThreadLocalMap这个对象threadLocals,在Thread.currentThread获取当前线程时,会初始化当前线程的threadLocals。

也就是说,每个Thread内部都有一个ThreadLocalMap,ThreadLocalMap伴随着Thread的整个生命周期,也会随着线程的销毁而终结

在这里插入图片描述
问:你知道ThreadLocal和Synchronized的区别吗?

都能对数据进行线程隔离吧,Synchronized是用时间换空间,ThreadLocal使用空间换时间。

问:为什么ThreadLocal所谓的Key(ThreadLocal)为弱引用,为什么Value不能为弱引用对象呢?

对于key(ThreadLocal)为弱引用问题: 如果key为强引用,引用的ThreadLocal的对象被回收了,但是ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏。

反之,如果key为弱引用, 引用的ThreadLocal的对象被回收了,由于ThreadLocalMap持有ThreadLocal的弱引用,即使没有手动删除,ThreadLocal也会被回收。value在下一次ThreadLocalMap调用set,get,remove的时候会被清除。

对于value为什么为强引用不使用弱引用的问题:如果value为弱引用,当value对象被回收了,ThreadLocalMap还持有value的弱引用,也会被回收,这样就会出现,存在key值,而value值不存在,这样的情况是不允许的。所以使用value使用强引用,当key被回收掉,在调用set、get、remove方法时会将key失效的value值清除掉。

问:ThreadLocal会造成内存泄漏么?

使用完ThreadLocal,没有正确的调用remove方法去清理,就会造成内存泄漏,虽然调用set和get方法的时候也会清理失效的key和对应的value,但是这并不是及时的,比如下面这个案例:

每个线程恰好只使用了一次set方法,没有及时地调用remove方法,这样很容易造成内存泄露,知道内存溢出。


import java.util.concurrent.*;
/*** -Xmx5m :设置堆内存为5m*/
public class ThreadLocalTest {static ThreadLocal<byte[]> threadLocal = new ThreadLocal<>();static ThreadPoolExecutor executorService = new ThreadPoolExecutor(10, 20, 60, TimeUnit.SECONDS,new LinkedBlockingDeque<>(100),Executors.defaultThreadFactory());public static void main(String[] args) {executorService.execute(() -> {threadLocal.set(new byte[1024 * 1024 * 2]);});executorService.execute(() -> {threadLocal.set(new byte[1024 * 1024 * 2]);});}
}

问:那如何才能正确的使用ThreadLocal呢?

  1. 用 private fianl static 修饰,主要使用为threadLocal作为每个线程内部的map的key,所以不需要总是创建,维持一个就可以,再者是因为static修饰,其就属于类本身,生命周期跟随类一致。因为ThreadLocal作为key,并且为弱引用,所以用private fianl static修饰,会防止threadLocal被gc掉,防止内存泄漏。
  2. 当然,在finally块中调用ThreadLocal#remove方法,就显得尤为重要。否则不仅可能会造成内存泄漏,在使用线程池的情况下还可能会读到脏数据。

问:那你谈谈ThreadLocal底层的这个hash表

这个hash表是一个Entry[],默认容量的是16,扩容因子是2/3,通过开放寻址法解决hash冲突,每次的索引值是通过如下得到(伪代码)

索引 = ThreadLocal#nextHashCode & (Entry[]#length - 1)// 保证索引的原子性
nextHashCode = AtomicInteger#getAndAdd(HASH_INCREMENT)

HASH_INCREMENT魔术值为0x61c88647,这个数是通过斐波那契散列求出来的

魔数 = 黄金分割比 (0.618)*2^32

每次扩容都会扩大2倍,这样的好处是减少Hash碰撞,让数据更散列更均匀的分布,更充分的利用数组的空间。

原因如下:
当数组的长度为2的幂次方时,len - 1的二进制为1...1...1,做&运算时,取决于key.threadLocalHashCode,也就是说key.threadLocalHashCode本身符合均匀分布,Hash算法的结果就是均匀的。

索引 = key.threadLocalHashCode & (len - 1)

在set方法的时候,如果发现有失效的key,就会去清除失效的key和对应的value。

清理的逻辑是:

  1. 从数组的当前坐标(失效key)向前遍历,找到最前面的失效的key,记录下来(假设此位置为a)。

  2. 再从数组的当前坐标(失效key)向后遍历,此时

    • 如果遇到同样的key就先替换,再开始从记录下来的位置a到此位置开始清理,清理过程中,如果发现此区间内存在有效的key,那么将这些key重新hash,放到别的位置上(因为采用了开放寻址法)
    • 如果没遇到同样的key,找到最后的失效的key,在这个区间开始清理。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

问:你知道父线程和子线程如何共享ThreadLocal吗?

可以用InheritableThreadLocal

InheritableThreadLocal实现子线程可以访问父线程的线程变量的实现原理如下:

  • InheritableThreadLocal通过重写createMap 和 getMap 方法让本地变量保存到了具体线程的inheritableThreadLocal变量中
  • 线程通过调用inheritableThreadLocal实例的set或get方法时,就会创建当前线程的inheritableThreadLocal变量
  • 当父线程创建子线程时,构造函数会把父线程中的inheritableThreadLocal变量里面的本地变量值复制一份保存到子线程的inheritableThreadLocal变量里

案例:

public class ThreadLocalTest {static InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>();static ThreadPoolExecutor executorService = new ThreadPoolExecutor(10,20,60,TimeUnit.SECONDS,new LinkedBlockingDeque<>(100),Executors.defaultThreadFactory());public static void main(String[] args) {threadLocal.set("hello");executorService.execute(() -> {System.out.println(threadLocal.get() + "=====1");});executorService.execute(() -> {System.out.println(threadLocal.get() + "=====2");});}
}

参考资料:

spring.io
京东云官方blog
货拉拉官方blog
ThreadLocal源码解析

相关文章:

应届生投腾讯,被面试官问了8个和 ThreadLocal 相关的问题。

问&#xff1a;谈一谈ThreadLocal的结构。 ThreadLocal内部维护了一个ThreadLocalMap静态内部类&#xff0c;ThreadLocalMap中又维护了一个Entry静态内部类&#xff0c;和Entry数组。 Entry类继承弱引用类WeakReference&#xff0c;Entry类有一个有参构造函数&#xff0c;参数…...

Linux命令scp用法

本文主要讲的是scp用法如果哪里不对欢迎指出&#xff0c;主页https://blog.csdn.net/qq_57785602?typeblogscp 可以在win系统使用&#xff0c;本文百分之八十写的是win系统怎么使用&#xff0c;在本地上到服务器文件,从服务器下载文件到本地用工具连接到公司服务器时&#xff…...

数据质量怎么监控

目录 一、任务基线级别 二、任务级别 & 表级别 三、字段级别 1. 对指标字段的监控 2. 对维度字段的监控 四、报表级别监控 五、总结 跑了几场面试&#xff0c;数据质量怎么监控是经常被问到的问题&#xff0c;仅次于自我介绍。 因为数据行业发展了几年&#xff0c;数…...

.NET Core 实现Excel的导入导出

.NET Core 使用NPOI实现Excel的导入导出前言NPOI简介一、安装相对应的程序包1.1、在 “管理NuGet程序包” 中的浏览搜索&#xff1a;“NPOI”二、新建Excel帮助类三、调用3.1、增加一个“keywords”模型类&#xff0c;用作导出3.2、添加一个控制器3.3、编写导入导出的控制器代码…...

排好队,一个一个来:宫本武藏教你学队列(附各种队列源码)

文章目录前言&#xff1a;理解“队列”的正确姿势一个关于队列的小思考——请求处理队列的两大“护法”————顺序队列和链式队列数组实现的队列链表实现的队列循环队列关于开篇&#xff0c;你明白了吗&#xff1f;最后说一句前言&#xff1a; 哈喽&#xff01;欢迎来到黑洞晓…...

C语言--动态内存管理1

目录前言动态内存函数介绍mallocfreecallocrealloc常见的动态内存错误对NULL指针的解引用操作对动态开辟空间的越界访问对非动态开辟内存使用free释放使用free释放一块动态开辟内存的一部分对同一块动态内存多次释放动态开辟内存忘记释放&#xff08;内存泄漏&#xff09;对通讯…...

HTTPS 的工作原理

1、客户端发起 HTTPS 请求 这个没什么好说的&#xff0c;就是用户在浏览器里输入一个 https 网址&#xff0c;然后连接到 server 的 443 端口。 2、服务端的配置 采用 HTTPS 协议的服务器必须要有一套数字证书&#xff0c;可以自己制作&#xff0c;也可以向组织申请&#xf…...

游戏开发中建议使用半兰伯特光照

游戏开发中建议使用半兰伯特光照模型 在基本光照模型中求出漫反射部分的计算公式: 漫反射 = 入射光线的颜色和强度(c light) * 材质漫反射系数 (m diffuse)* 表面法线(n) * 其光源防线 (I) 在shader中为了不让 n和i的点乘结果为负数,即使用了saturate函数让值截取在[0,1]区…...

JavaScript到底如何存储数据?

1.var的迷幻操作 普遍的观点&#xff1a;JavaScript中的基本数据类型是保存在栈空间&#xff0c;而引用数据类型则是保存在堆空间里, 是否正确&#xff1f; 浏览器环境下JavaScript变量类型的运行实践结果: var a 10;console.log(a);console.log(window.a); console.log(wind…...

python实战应用讲解-【numpy专题篇】numpy应用案例(一)(附python示例代码)

目录 用Python分析二手车的销售价格 用Python构建GUI应用的铅笔草图 需要的包 实现步骤 完整代码 用Python分析二手车的销售价格 如今&#xff0c;随着技术的进步&#xff0c;像机器学习等技术正在许多组织中得到大规模的应用。这些模型通常与一组预定义的数据点一起工作…...

网络割接项目

某企业准备采购2台华为设备取代思科旧款设备,针对下列问题作出解答。 (1)做设备替换的时候,如何尽可能保证业务稳定性,请给出解决方案。 a)对现网拓扑进行分析,分析现网拓扑的规划(链路类型、cost、互联IP、互联接口等信息)、分析现网流量模型(路由协议、数据流向特…...

SpringBoot整合数据可视化大屏使用

1 前言 DataV数据可视化是使用可视化应用的方式来分析并展示庞杂数据的产品。DataV旨让更多的人看到数据可视化的魅力,帮助非专业的工程师通过图形化的界面轻松搭建专业水准的可视化应用,满足您会议展览、业务监控、风险预警、地理信息分析等多种业务的展示需求, 访问地址:h…...

蓝桥杯Web前端练习题-----水果拼盘

一、水果拼盘 介绍 目前 CSS3 中新增的 Flex 弹性布局已经成为前端页面布局的首选方案&#xff0c;本题可以使用 Flex 属性快速完成布局。 准备 开始答题前&#xff0c;需要先打开本题的项目代码文件夹&#xff0c;目录结构如下&#xff1a; ├── css │ └── style.…...

[攻城狮计划]如何优雅的在RA2E1上运行RT_Thread

文章目录[攻城狮计划]|如何优雅的在RA2E1上运行RT_Thread准备阶段&#x1f697;开发板&#x1f697;开发环境&#x1f697;下载BSP&#x1f697;编译烧录连接串口总结[攻城狮计划]|如何优雅的在RA2E1上运行RT_Thread &#x1f680;&#x1f680;开启攻城狮的成长之旅&#xff0…...

1.linux操作命令

1. pwd -> 打印当前绝对工作路径。 2. ls -> 查看目录的文件名 ls -> 默认列出当前目录的全部文件名 ls . -> 列出当前目录的全部文件名(.代表当前目录) ls / -> 列出根目录下的全部文件命名 ls -a -> 列出当前目录下全部文件名(包括隐藏…...

STL--vector

vector 头文件 #include<vector>向量的定义&#xff1a; vector<int> vec&#xff1b;//定义一个vec型的向量a vector<int> vec(5); //定义一个初始大小为5的向量 vector<int> vec(5,1); //初始大小为5&#xff0c;值都为1的向量二维数组&#xff1…...

Java每日一练(20230324)

目录 1. 链表插入排序 &#x1f31f;&#x1f31f; 2. 最接近的三数之和 &#x1f31f;&#x1f31f; 3. 寻找旋转排序数组中的最小值 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一…...

你掌握了吗?在PCB设计中,又快又准地放置元件

在印刷电路板设计中&#xff0c;设置电路板轮廓后&#xff0c;将零件(占地面积)调用到工作区。然后将零件重新放置到正确的位置&#xff0c;并在完成后进行接线。 组件放置是这项工作的第一步&#xff0c;对于之后的平滑布线工作是非常重要的工作。如果在接线工作期间模块不足…...

springboot学生综合测评系统

031-springboot学生综合测评系统演示录像2022开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&…...

【Unity3D】法线贴图和凹凸映射

1 法线贴图原理 表面着色器中介绍了使用表面着色器进行法线贴图&#xff0c;实现简单快捷。本文将介绍使用顶点和片元着色器实现法线贴图和凹凸映射&#xff0c;实现更灵活。 本文完整代码资源见→法线贴图和凹凸映射。 1&#xff09;光照原理 Phong 光照模型和 Blinn Phong 光…...

代码误写到master分支(或其他分支),此时代码还未提交,如何转移到新建分支?

问题背景 有时候&#xff0c;我们拿到需求&#xff0c;没仔细看当前分支是什么&#xff0c;就开始撸代码了。完成了需求或者写到一半发现开发错分支了。 比如此时新需求代码都在master分支上&#xff0c;提交必然是不可能的&#xff0c;所有修改还是要在新建分支上进行&#x…...

java多线程之线程安全(重点,难点)

线程安全1. 线程不安全的原因:1.1 抢占式执行1.2 多个线程修改同一个变量1.3 修改操作不是原子的锁(synchronized)1.一个锁对应一个锁对象.2.多个锁对应一个锁对象.2.多个锁对应多个锁对象.4. 找出代码错误5. 锁的另一种用法1.4 内存可见性解决内存可见性引发的线程安全问题(vo…...

如何免费使用chatGPT4?无需注册!

Poe体验真滴爽首先提大家问一个大家最关心的问题如何在一年内赚到一百万&#xff1f;用个插件给他翻译一下体验地址效果是非常炸裂的&#xff0c;那么我就将网址分分享给大家https://poe.com/前提&#xff1a;要有魔法&#xff0c;能够科学shangwangChatGPT-3 随便问GPT-4 模型…...

Android Flutter在点击事件上添加动画效果

在Android App的开发项目中&#xff0c;我们需要在点击事件上实现一个动画效果来提高用户的体验度。比如闲鱼底部中间按钮的那种。该怎么实现呢&#xff1f; 一起来看看吧 实现效果如图&#xff1a; ​实现思路 根据UI的设计图&#xff0c;对每个模块设计好动画效果&#xff0…...

VSCode嵌入式开发环境搭建

Vscode开发环境搭建 看这个链接就可以了&#xff0c;后面下载调试有点问题看下3.3。 在VSCode上部署STM32F1的开发环境 1. MXCube配置工程生成Makefile文件 借助正确的编译工具链进行编译&#xff0c; 2. 编译工具链搭建 编译工具链使用GCC的ARM版本 arm-none-eabi-gcc &am…...

数据结构之栈的使用

栈是计算机科学中一个重要的数据结构。它是一种特殊的线性表&#xff0c;只允许在一端进行进出操作。这一端被称为栈顶&#xff0c;另外一端被称为栈底。栈的特点是后进先出&#xff0c;即最后进入栈的元素会先被弹出栈。栈的应用广泛&#xff0c;例如在编译器中&#xff0c;栈…...

QMessageBox手动添加按钮并绑定按钮的信号

视频展示效果&#xff08;结合代码看效果更佳哦&#xff0c;代码在最下面&#xff09;&#xff1a; QMessageBox手动添加有重试效果的按钮效果图&#xff1a; 点击详细文本之后展开如下图&#xff1a; 图标可选&#xff1a; QMessageBox::Critical错误图标QMessageBox::NoIco…...

【C++进阶】位图和布隆过滤器

文章目录位图位图概念位图使用场景位图的结构构造setresettest完整代码布隆过滤器布隆过滤器概念布隆过滤器结构构造setresettest完整版代码位图 位图概念 所谓位图&#xff0c;就是用每一位来存放某种状态&#xff0c;适用于海量数据&#xff0c;数据无重复的场景。通常是用…...

Android开发-Android UI与布局

01 Android UI 1.1 UI 用户界面(User Interface&#xff0c;简称 UI&#xff0c;亦称使用者界面)是系统和用户之间进行交互和信息交换的媒介&#xff0c;它实现信息的内部形式与人类可以接受形式之间的转换。软件设计可分为两个部分&#xff1a;编码设计与UI设计。 1.2 Andr…...

在不丢失数据的情况下解锁锁定的 Android 手机的 4 种方法

尽管您可以使用指纹解锁手机&#xff0c;但大多数智能手机都需要 PIN 码、图案或字母数字代码作为主密码。如果您有一段时间没有输入手机密码&#xff0c;很容易忘记。正是由于这个原因&#xff0c;即使您打开了指纹解锁&#xff0c;大多数智能手机也会让您每天至少输入一次 PI…...

合肥网站建设公司 推荐/免费刷粉网站推广免费

关于c语言中的指针的一些相关的问题: 1.int *p; 2.int **p; 3.int *p[10]; 4.int (*p)[10]; 5.int *p(int); 6.int (*p)(int); 7.int (*p[10])(int); 这七个难度还不是很大&#xff0c;相信大多数读者都能够答的出来。 答案&#xff1a; 1.一个指向整型数据的指针 2.一个指针的…...

wordpress开启伪静态/哈尔滨seo关键词排名

离散数学实验报告3 文章目录离散数学实验报告3一、实验题目二、实验目的三、实验要求需求分析&#xff1a;输入形式与输入范围概要设计&#xff1a;使用的数据结构与算法&#xff1a;程序流程&#xff1a;详细代码一、实验题目 实验题目&#xff1a;平面图判定及对偶图的求解 实…...

wordpress优缺点/网络营销方案ppt

容斥原理 设\(S_1,S_2,...,S_n\)为\(n\)个有限集合&#xff0c;\(|S|\)代表集合\(S\)的大小&#xff0c;则有 \[\left | \bigcup_{i1}^nS_i \right |\sum_{i1}^n|S_i|-\sum_{1\leq i \leq j \leq n}|S_i\cap S_j|...(-1)^{n1}\left | \bigcap_{i1}^nS_i \right |\] 多重集组合数…...

广州 网站建设公司/百度官方下载

我在使用cherrypy3.2.4上传文件时遇到问题。(Python 2.7)我无法获取上传文件的原始数据。我试图调试如何从响应中获取数据值&#xff0c;但没有成功。有人知道怎么解决这个问题吗&#xff1f;在皮奥特这是我使用的代码&#xff1a;def index(self):return """Up…...

书籍网站建设的目的/企业培训课程清单

case:Spark向kafka中写入数据 对于每个partition的每条记录&#xff0c;我们都需要创建KafkaProducer&#xff0c;然后利用producer进行输出操作&#xff0c;注意这里我们并不能将KafkaProducer的新建任务放在foreachPartition外边&#xff0c;因为KafkaProducer是不可序列化的…...

哈尔滨网站建设制作哪家便宜/搜索引擎营销与seo优化

【零样本知识蒸馏】(八)CVPR 2020:Dreaming to Distill: Data-free Knowledge Transfer via DeepInversion 论文地址:代码地址:主要思路:基本符号:知识蒸馏:DeepDream:具体实现:DI:ADI:实验结果:论文地址: https://arxiv.org/abs/1912.08795 代码地址: https…...