ThreadLocal的简单理解

🚀 优质资源分享 🚀

学习路线指引(点击解锁)知识定位人群定位
🧡 Python实战微信订餐小程序 🧡进阶级本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
💛Python量化交易实战💛入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

目录* 一、背景

  • 二、ThreadLocal解决的问题
  • 三、如何创建一个ThreadLocal实例
  • 四、ThreadLocal如何做到线程变量隔离
    • 1、理解3个类
    • 2、看下set方法是如何实现的
    • 3、看看 get 方法如何实现
  • 五、ThreadLocalMap中的hash冲突是如何处理的
    • 1、ThreadLocal对象的hash值是怎样的
    • 2、解决hash冲突
  • 六、ThreadLocal内存泄漏

一、背景

最近有人问我ThreadLocal是如何做到在每个线程中的值都是隔离的,此处写篇文章来简单记录下。

二、ThreadLocal解决的问题

  1. 该数据属于该线程Thread自身,别的线程无法对其影响。(需要注意:需要调用ThreadLocal的remove方法)
  2. 不存在线程安全问题。(因为ThreadLocal类型的变量只有自身的线程可以访问,所以这点是成立的。)

比如:

用户登录成功后,需要将登录用户信息保存起来,以方便在系统中的任何地方都可以使用到,那么此时就可以使用ThreadLocal来实现。例如:Spring Security中的ThreadLocalSecurityContextHolderStrategy类。

三、如何创建一个ThreadLocal实例

private static final ThreadLocal USER\_NAME = new ThreadLocal<>();

ThreadLocal的实例推荐使用private static final来修饰。

四、ThreadLocal如何做到线程变量隔离

1、理解3个类

  1. ThreadLocal: 此类提供了一个简单的set,get,remove方法,用于设置,获取或移除 绑定到线程本地变量中的值。
  2. ThreadLocalMap: 这是在ThreadLocal中定义的一个类,可以简单的将它理解成一个Map,不过它的key是WeakReference弱引用类型,这样当这个值没有在别的地方引用时,在发生垃圾回收时,这个map的key会被自动回收,不过它的值不会被自动回收。
static class Entry extends WeakReference> {Object value;Entry(ThreadLocal k, Object v) {// key 弱引用super(k);// 值强引用value = v;}
}
  1. Thread:这个是线程类,在这个类中存在一个threadLocals变量,具体的类型是ThreadLocal.ThreadLocalMap

2、看下set方法是如何实现的

public void set(T value) {// 获取当前线程Thread t = Thread.currentThread();// 获取绑定到这个线程自身的 ThreadLocalMap,这个ThreadLocalMap是从Thread类的`threadLocals`变量中获取的ThreadLocalMap map = getMap(t);if (map != null) {// 向map中设置值,key为 ThreadLocal 对象的实例。map.set(this, value);} else {// 如果map不存在,则创建出来。createMap(t, value);}
}

通过上方的代码,我们可知: 当我们向ThreadLocal中设置一个值,会经过如下几个步骤:

  1. 获取当前线程Thread
  2. 获取当前线程的 ThreadLocalMap 对象。
  3. ThreadLocalMap中设置值,key为ThreadLocal对象,值为具体的值。

3、看看 get 方法如何实现

public T get() {// 获取当前线程Thread t = Thread.currentThread();// 获取这个线程自身绑定的 ThreadLocalMap 对象ThreadLocalMap map = getMap(t);if (map != null) {// this是ThreadLocal对象,获取Map中的Entry对象ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")// 获取具体的值T result = (T)e.value;return result;}}// 设置初始值return setInitialValue();
}

从上方的get 和 set 方法可以得知,通过往ThreadLocal对象中设置值或获取值,其实是最终操作到Thread对象中的threadLocals字段中,而这个字段是Thread自身的,因此做到了隔离。

五、ThreadLocalMap中的hash冲突是如何处理的

1、ThreadLocal对象的hash值是怎样的

private final int threadLocalHashCode = nextHashCode();// 该 ThreadLocal 对象自身的hash code值private final int threadLocalHashCode = nextHashCode();// 从0开始private static AtomicInteger nextHashCode = new AtomicInteger();// 每次递增固定的值private static final int HASH\_INCREMENT = 0x61c88647;// hash code 值计算private static int nextHashCode() {return nextHashCode.getAndAdd(HASH_INCREMENT);}

从上方的代码中可以,ThreadLocal类在实例化出来之后,它的hash code值(threadLocalHashCode)就是固定的,即使ThreadLocal调用了set方法,设置了别的值,它的hash code值也不会发生变化。

此字段threadLocalHashCodeThreadLocal对象的hash值,在ThreadLocalMap中需要用到这个hash值。

2、解决hash冲突

ThreadLocalMap hash冲突

ThreadLocalMap解决hash冲突的办法很简单。就是通过线性探测法。如果发生了冲突,就去找数组后面的可用位置。具体看上图。演示的是A和B 2个ThreadLocal对象,然后发生了冲突,A和B存在的位置在那个地方。

六、ThreadLocal内存泄漏

ThreadLocal为什么会存在内存泄漏呢?

这是因为ThreadLocalMap中的keyWeakReference类型,也就是弱引用类型,而弱引用类型的数据在没有外部强引用类型的话,在发生gc的时候,会自动被回收掉。注意: 此时是key被回收了,但是value是没有回收的。因此在ThreadLocalMap中的Entry[]中可能存在keynull,但是value是具体的值的对象,因此就发生了内存泄漏。

解决内存泄漏:

当我们使用完ThreadLocal对象后,需要在适当的时机调用ThreadLocal#remove()方法。 否则就只有等Thread自动退出才能清除,如果是使用了线程池,Thread会重用,清除的机会就更难。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/400781.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JMS 在 SpringBoot 中的使用

当前环境 Mac OS 10.11.xdocker 1.12.1JDK 1.8SpringBoot 1.5前言 基于之前一篇“一个故事告诉你什么是消息队列”&#xff0c;了解了消息队列的使用场景以及相关的特性。本文主要讲述消息服务在 JAVA 中的使用。 市面上的有关消息队列的技术选型非常多&#xff0c;如果我们的代…

MSP432P401R TI Drivers 库函数学习笔记(二)认识TI-RTOS (TI-POSIX)

目录简介TI-RTOSFreeRTOSPOSIX运行时对象查看器 (Runtime Object Viewer)TI-POSIX 介绍在源代码中使用 POSIXTI-POSIX支持的函数摘要线程函数调用的前后关系线程管理线程属性线程同步障碍属性条件变量条件变量属性互斥锁互斥属性读写锁定读写锁属性辅助函数调用的前后关系时钟消…

arcgis创建postgre企业级数据库

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

[floyd+路径输出]HDU1385 Minimum Transport Cost

题目链接 题目翻译: 有N个城市&#xff0c;然后直接给出这些城市之间的邻接矩阵&#xff0c;矩阵中-1代表那两个城市无道路相连&#xff0c;其他值代表路径长度。 如果一辆汽车经过某个城市&#xff0c;必须要交一定的钱(可能是过路费)。 现在要从a城到b城&#xff0c;花费为路…

MSP432P401R TI Drivers 库函数学习笔记(三)认识任务的创建及图形化配置

目录任务的简单创建图形化配置上手简简单单点个灯配置引脚建立任务实验结果整体代码main.cmyTask.cmyTask.h平台&#xff1a;Code Composer Studio 10.4.0 MSP432P401R SimpleLink™ 微控制器 LaunchPad™ 开发套件 (MSP-EXP432P401R) 任务的简单创建 根据上篇机翻的函数作用…

JavaScript实现自适应宽度的瀑布流

摘要: 主要介绍瀑布流的一种实现方法&#xff1a;绝对定位(css)javascriptajaxjson。简单一点如果不做滚动加载的话就是绝对定位(css)javascript了&#xff0c;ajax和json是滚动加载更多内容的时候用到的。 这样的布局并不陌生&#xff0c;从2011年Pinterest创立以来&#xff0…

.net web 开发平台- 表单设计器 一(web版)

如今为了适应需求的不断变化&#xff0c;动态表单设计器应运而生。它主要是为了满足界面的不断变化和提高开发速度。比如&#xff1a;一些页面客户可能也无法确定页面的终于布局&#xff0c;控件的位置&#xff0c;在哪种情况下显示或不显示等可能须要随时改动。为了应对这些需…

.NET程序配置文件操作(ini,cfg,config)

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

MSP432P401R TI Drivers 库函数学习笔记(四)GPIO

目录API头文件函数 (机翻)宏GPIO驱动程序api返回的通用状态代码GPIO_PinConfig输出引脚配置宏GPIO_PinConfig输入引脚配置宏GPIO_PinConfig中断配置宏特殊的GPIO_PinConfig配置宏类型别名示例配置引脚示例配置外部中断示例上机实战配置引脚main.cmyTask.cmyTask.h实验结果平台&…

# Vue3 toRef 和 toRefs 函数

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

二分检索函数lower_bound()和upper_bound()

二分检索函数lower_bound()和upper_bound() 一、说明 头文件&#xff1a;<algorithm> 二分检索函数lower_bound()和upper_bound() lower_bound()&#xff1a;找到大于等于某值的第一次出现upper_bound()&#xff1a;找到大于某值的第一次出现必须从小到大排序后才能用 内…

MSP432P401R TI Drivers 库函数学习笔记(五)PWM

目录API (机翻)函数上机实战配置引脚PWM初始化&#xff0c;实现简易呼吸灯的效果实验结果完整代码myPWM.cmyPWM.hmyTask.cmyTask.hmain.cmain.h平台&#xff1a;Code Composer Studio 10.4.0 MSP432P401R SimpleLink™ 微控制器 LaunchPad™ 开发套件 (MSP-EXP432P401R) API …

防火墙配置十大任务之十,构建虚拟防火墙

防火墙配置任务十构建虚拟防火墙任务拓扑图10.11.inside区域的交换机的基本配置&#xff0c;在交换机上开启vlan2&#xff0c;vlan3&#xff0c;vlan4.三个vlan。图10.22.outside区域的Internet基本配置。图10.33.交换机上连接防火墙接口的配置。图10.44.inside区域各个PC的主机…

使用纯 CSS 实现超酷炫的粘性气泡效果

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

MSP432P401R TI Drivers 库函数学习笔记(六)UART 串口

目录API (机翻)上机实战配置初始化和实验实验结果整体代码myUart.cmyUart.hmyTask.cmyTask.hmain.cmain.h平台&#xff1a;Code Composer Studio 10.4.0 MSP432P401R SimpleLink™ 微控制器 LaunchPad™ 开发套件 (MSP-EXP432P401R) API (机翻) 官方UART API 手册 void UA…

Linux 批量杀死进程(详细版本)

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

MSP432 库函数实现 PID 电机调角度、调速

目录引脚配置PWM引脚外部中断测量编码器引脚配置代码部分初始化编码器解读Encoder.cEncoder.h测速和控制部分卡尔曼滤波器&#xff0c;用于对所测速度进行滤波kalman.ckalman.h实验效果速度滤波效果控速效果控角效果平台&#xff1a;Code Composer Studio 10.4.0 MSP432P401R …

20.网页卷去的距离与偏移量

我们先来看看下面的图&#xff1a; scrollLeft:设置或获取位于给定对象左边界与窗口中目前可见内容的最左端之间的距离 &#xff0c;即左边灰色的内容。 scrollTop:设置或获取位于对象最顶端与窗口中可见内容的最顶端之间的距离 &#xff0c;即上边灰色的内容。 offsetLeft:获取…

【电赛】一阶卡尔曼滤波器 滤波效果良好

目录代码kalman.ckalman.h滤波效果很久以前抄的&#xff0c;忘了是从哪弄的了 我把它改成了这种结构体指针传参的形式&#xff0c;方便在比赛中应用。应用举例见MSP432 PID 电机调角度、调速。 它曾助力笔者获2020年电赛省一等奖。 代码 Q:过程噪声协方差 Q参数调滤波后的曲线…

计算机是如何启动的?

从打开电源到开始操作&#xff0c;计算机的启动是一个非常复杂的过程。 我一直搞不清楚&#xff0c;这个过程到底是怎么回事&#xff0c;只看见屏幕快速滚动各种提示......这几天&#xff0c;我查了一些资料&#xff0c;试图搞懂它。下面就是我整理的笔记。 零、boot的含义 先问…