如何理解ThreadLocal

news2024/11/23 22:34:19

ThreadLocal的基本概念

在并发编程中,多个线程访问同一个变量,可能会出现线程安全问题、为了保证在多线程环境下访问共享变量的安全性,通常在访问共享变量的时候加锁,以实现线程同步的效果。
使用同步锁机制保证多线程访问共享变量的安全性的原理如下图。该机制能够保证同一时刻只有一个线程访问共享变量,从而确保在多线程环境下访问共享变量的安全性。
在这里插入图片描述
另外,为了更加灵活地确保线程的安全性,JDK中提供了一个ThreadLocal类,ThreadLocal类能够支持本地变量。在使用ThreadLocal类访问共享变量时,会在每个线程的本地内存中保存一份副本。在多个线程同时对这个变量进行读写操作时,实际操作的时本地内存中的副本,多个线程之间互不干扰,从而避免了线程安全的问题。使用ThreadLocal访问共享变量的示意图如下:
在这里插入图片描述

ThreadLocal的核心原理

ThreadLocal能够保证每个线程操作的都是本地内存中的变量副本。在底层实现上,调用ThreadLocal的set()方法会将本地变量保存在具体线程的内存空间中,ThreadLocal并不负责存储具体的数据。

Thread源码

在Thread类的源码中,定义了两个ThreadLocal.ThreadLocalMap类型的成员变量,分别为threadLocals和inheritableThreadLocals.

    ThreadLocal.ThreadLocalMap threadLocals = null;
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

在Thread类中定义成员变量threadLocals和inherittableThreadLocals,两者的初始值都为null,并且只有当线程第一次调用ThreadLocal或者InheritableThreadLocals的set()方法或者get()方法是才会实例化变量。
通过ThreadLocal为每个线程保存的本地变量不是存在ThreadLocal实例中的,而是存在调用线程的threadLocals变量中的。也就是说,调用ThreadLocal的set()方法存储的本地变量在具体线程的内存空间中,而ThreadLocal类支提供了set()和get()方法来存储和读取本地变量的值,当调用ThreadLocal类的set()方法时,把要存储的值存储在调用线程的threadLocals变量中,当调用ThreadLocal类的get()方法时,从当前线程的threadLocals变量中获取保存的值。

set()方法

  public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

从ThreadLocal类中的set()方法的源码可以看出,在set()方法中,会先获取调用set()方法的线程,然后使用当前线程对象作为key调用getMap()方法获取ThreadLocalMap对象,getMap()方法源码如下:

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

可以看出调用getMap()方法获取的就是当前线程中定义的threadLocals成员变量。获取ThreadLocalMap对象后,判断该对象是否为空,不为空则把value设置到Thread类的threadLocals成员变量中。保存数据时传递的key为当前ThreadLocal的this对象,而传递的value为调用set()方法传递的值。
如果当前线程的ThreadLocals成员变量为空,则调用createMap()方法来实例化当前线程的threadLocals成员变量,并保存value值。createMap()方法源码如下:

    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

get()方法

 public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

get()方法通过调用getMap()方法并传入当前线程来获取threadLocals成员变量,然后判断当前线程的threadLocals成员变量是否为空。如果不为空,则直接返回当前线程threadLocals成员变量中存储的本地变量的值。如果为空,则调用setInitialValue()方法初始化threadLocals成员变量的值。setInitialValue()的源码如下:

 private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

setInitialValue()方法与set()方法大致相同,只不过setInitialValue()方法会先调用initialValue()方法来初始化value的值,最后返回value的值。initialValue()方法源码如下:

    protected T initialValue() {
        return null;
    }

initialValue()方法直接返回null,方法的具体逻辑会交由ThreadLocal类中的子类实现。

remove()方法

     public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

根据调用的getMap()方法获取当前线程的threadLocals成员变量,如果当前线程的threadLocals成员变量不为空,则直接从当前线程的threadLocals成员变量中移除当前threadLocal对象对应的value值。

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

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

相关文章

ChatGPT | 一文详解ChatGPT(学习必备)

本文概要 本篇文章主要介绍ChatGPT的产生和使用体验,适合不了解ChatGPT或者了解不够透彻的小伙伴,文中的描述非常详细,干货满满,感兴趣的小伙伴快来一起学习吧! 🌟个人简介 ☀️大家好!我是新人…

信息的相关性和冗余度:信息在整个文明中的作用

文章目录 I 古埃及的象形文字1.1 罗塞塔石碑1.2 古埃及文字音节和希腊字母的对应表1.3 破解古埃及文字 I 古埃及的象形文字 1.1 罗塞塔石碑 这个石碑是在公元前196年埃及国王托勒密五世加冕一周年的诏书。 在此前大约一百年,埃及已经被来自希腊北方城邦的亚历山大…

C++------引用

一、 引用概念 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。 类型& 引用变量名(对象名) 引用实体; int main() {//一个变量可以有多个引用…

LWIP协议与TCP/IP

1. 学习一个东西,先了解这个东西是干什么用的,哪些场景会用到它,与自己已经掌握的其他知识的联系 a. 例如:LWIP这个东西是干什么用的:他就是一个裁剪后保持大部分TCP/IP功能的协议。用少量的资源消耗实现一个较为完整的…

大数据实战 --- 淘宝用户行为数据分析

目录 开发环境 数据描述 功能需求 数据准备 数据清洗 用户行为分析 找出有价值的用户 开发环境 HadoopHiveSparkHBase 启动Hadoop:start-all.sh 启动zookeeper:zkServer.sh start 启动Hive: nohup hiveserver2 1>/dev/null 2>…

从零开始的ChatGLM 配置详细教程

从零开始的ChatGLM配置教程 文章目录 从零开始的ChatGLM配置教程一,前言二,环境配置1、下载ChatGLM项目2、配置程序运行环境 三、在HuggingFace下载chatGLM-6B模型1,安装 Git Lfs2,下载相关文件3,在HuggingFace中下载相…

什么是隔离放大器

隔离放大器(也称为单位增益放大器)是一种提供隔离的运算放大器电路电路的一部分与另一部分电路不同,这样就不会在电路的一部分中使用、消耗或浪费功率。 现在将对此进行彻底解释,因为这乍一看似乎是一个令人生畏的话题&#xff0c…

【TCP Wrappers】

目录 一、保护原理二、TCP Wrappers 保护机制的两种方式三、TCP Wrappers 的访问策略四、TCP Wrappers 机制的基本原则1、允许所有,拒绝个别2、允许个别,拒绝所有实列 一、保护原理 二、TCP Wrappers 保护机制的两种方式 1.直接使用 tcpd 程序对其他服务…

JavaFx 自定义封装 DateTimePicker 时间选择组件(支持时分秒)

JavaFx DateTimePicker 时间选择组件 javaFx 自定义时间选择组件 DateTimePicker, javaFx 源代码不支持时分秒选择,该代码组件支持时分秒选择,同时也支持清空、取消、此刻等操作! 效果如下图所示: 源码地址&#xff…

AXI4总线学习笔记

AXI4 总线是 ARM 公司开发的一种总线,广泛应用于 Xilinx 的 IP 核中,比如笔者近期涉及 DDR 的读写控制,需要用到 MIG IP 核,这个 IP 核就通过 AXI4 总线进行控制。 AXI4 共有 5 种通道:读地址通道 ARC,读数…

虽然音视频开发只是功能组件开发,但薪资远高于普通开发岗……

首先要明白一件事情,音视频开发是功能组件开发而不是应用开发。应用开发的具体需求基本上是定制化的,而且需求一直在改,比如今天加个按钮,明天改个风格,只要应用还在天天都有活干。而功能组件开发的需求大多都比较统一…

一文详解过滤器Filter、拦截器Interceptor和切面Aspect的区别

目录 Filter过滤器 作用 应用场景 拦截器Interceptor Aspect切片 三者对比 执行顺序 拦截层面 过滤器Filter和拦截器Interceptor的区别 Filter过滤器 Filter 过滤器它是 JavaWeb 的三大组件之一 三大组件分别是:Servlet 程序、Listener 监听器、Filter 过滤…

vue3组件间怎么通信?简述一下通信方式

在写 vue3 的项目中,我们都会进行组件通信,除了使用 pinia 公共数据源的方式除外,我们还可采用那些更简单的API方法呢?给大家介绍介绍几种父子组件和子父组件通信的方式。 1、父子组件通信 1.1 defineProps 父子组件通信我们第一…

【Redis】Redis数据结构——链表

【Redis】Redis数据结构——链表 注意事项: 本文第三点redis中操作列表的相关命令可参考博文: 【Redis】Redis基础命令集详解_Etui۹(・༥・)و ̑̑的博客-CSDN博客 本文参考内容如下: 1、Redis数据结构——链表 - 随心…

MySQL_第07章_单行函数

第07章_单行函数 讲师:尚硅谷 - 宋红康(江湖人称:康师傅) 官网: http://www.atguigu.com 1. 函数的理解 1.1 什么是函数 函数在计算机语言的使用中贯穿始终,函数的作用是什么呢?它可以把我…

音视频八股文(3)--ffmpeg常见命令(2)

07-ffplay命令播放媒体 播放本地文件 播放本地 MP4 视频文件 test.mp4 的命令,从第 2 秒位置开始播放,播放时长为 10 秒,并且在窗口标题中显示 “test time”: ffplay -window_title "test time" -ss 2 -t 10 -autoe…

[计算机图形学]辐射度量学、渲染方程与全局光照(前瞻预习/复习回顾)

一、前言 我们前面讲到的Blinn-Phong着色,Whitted-Style光线追踪都有一定问题,那就是它们并没有严格的按照物理规则定义各个变量。比如,Blinn-Phong中的光的强度,并没有一个确切的单位。同时Whitted-Style光线追踪我们也做了很多简…

二十分钟深入详解<二叉搜索树>!!!

目录 前文 一,什么是二叉搜索树? 1.1 二叉搜索树的概念 二, 二叉搜索树的常用操作及其实现 2.1 查找 2.2 插入 2.3 删除 三,二叉搜索树的应用 3.1 K模型 3.2 KV模型 四,二叉搜索树的性能分析 五,…

SolidWorks建模|渲染装饰件

使用SOLIDWORKS软件建模是许多工程师的选择,对于SOLIDWORKS渲染,也有很多问题,接下来,我们就用SOLIDWORKS建模渲染装饰件的例子来讲解。 1.点击“插入”-“曲面”-“拉伸曲面”,选择上视基准面作为草绘平面&#xff0…

CC2564CRVMR无线音频解决方案、ADE9000ACPZ模拟前端 (AFE) 电路图【MX66L2G45GXRI00 2Gb】FLASH - NOR

CC2564CRVMR 双模蓝牙控制器是一个完整的Bluetooth BR、EDR和低能耗HCI解决方案,可减少设计工作量并缩短上市时间。CC2564C器件基于TI的第七代蓝牙内核,提供符合蓝牙4.2标准的产品验证解决方案。当与微控制器单元 (MCU) 耦合时,该HCI器件具有…