并发编程专题-4:ThreadLocal 原理解析

并发编程系列之ThreadLocal实现原理 并发编程系列之ThreadLocal实现原理。ThreadLocal是一个线程的本地变量,可以理解为线程的变量,在线程执行过程随时可以访问。ThreadLocal变量,只有当前线程才能访问,其它线程不能访问,所以本质上ThreadLocal就是线程安全的。所以ThreadLocal的作用和上面例子说的局部变量一样是线程安全的。 阅读详情

1、ThreadLocal的使用

防止任务在共享资源上产生冲突的一种方式是根除对变量的共享,使用线程的本地存储为使用相同变量的不同线程创建不同的存储。

下面是一个ThreadLocal的实例。这里我们使用了静态的全局变量ThreadLocal对象来保存Integer类型的值。
我们在不同的线程中将指定的数字传入到threadLocal中进行保存。然后,再将其读取出来:

private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();

public static void main(String...args) {
    threadLocal.set(-1);
    ExecutorService executor = Executors.newCachedThreadPool();
    for (int i=0; i<5; i++) {
        final int ii = i; // i不能是final的,创建临时变量
        executor.submit(new Runnable() {
            public void run() {
                threadLocal.set(ii);
                System.out.println(threadLocal.get());
            }
        });
    }
    executor.shutdown();
    System.out.println(threadLocal.get());
}

从程序的执行结果可以看出,每个线程都正确地读取出来了保存到ThreadLocal中的数据。

所以,我们总结一下ThreadLocal的作用就是,存储在ThreadLocal中的变量是线程安全的,每个线程只能读取出自己存储的值。

通常它的使用方式就是定义一个静态全局的ThreadLocal实例,然后每个线程使用它来读写只有自己会用到的数据。
比如,我们要为每个线程创建了一个数据库连接,并且该连接只允许该线程自己使用,那么可以将它存储在ThreadLocal中,
然后在用到的地方获取。

看了上面的例子,也许你会又以下一些问题:

  1. ThreadLocal中存储的值是如何保证绝对的线程安全的?
  2. 那么这些值是存储在什么地方?
  3. 是静态类型的还是实例类型的?
  4. 如果某个线程执行完毕了,被销毁了,那么这些存储的值会被怎么处理呢?
  5. ……

带着上面的这些问题,我们来看下在JDK源码中ThreadLocal是如何实现的。

2、ThreadLocal的作用原理

我们还是先从读取的操作来看。

以下是ThreadLocal中get()方法的代码:

public T get() {
    Thread t = Thread.currentThread();  // 1
    ThreadLocalMap map = getMap(t);  // 2
    if (map != null) {  // 3
        ThreadLocalMap.Entry e = map.getEntry(this);  // 4
        if (e != null) {
            T result = (T) e.value; // 5
            return result;
        }
    }
    return setInitialValue();
}

这里首先会再步骤1中获取到当前线程的实例,然后在步骤2中通过getMap()方法,使用当前的线程的ThreadLocalMap。
这里的ThreadLocalMap的定义如下:

static class ThreadLocalMap {

    static class Entry extends WeakReference<ThreadLocal<?>> {
        Object value;
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
	
    private Entry[] table;
	
    private Entry getEntry(ThreadLocal<?> key) {
        int i = key.threadLocalHashCode & (table.length - 1);
        Entry e = table[i];
        if (e != null && e.get() == key)
            return e;
        else
            return getEntryAfterMiss(key, i, e);
    }
	
    // ...
}

然后,我们看下getMap()方法的定义:

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

也就是说实际上当我们调用get()方法的时候,会先获取当前线程中的threadLocals字段,该字段是ThreadLocalMap类型的。
然后,我们使用当前的ThreadLocal实例作为键来从哈希表中获取到一个Entry,而实际的值就保存再Entry的value字段中。

就像上面的getEntry()方法定义的那样,似乎这里的哈希表只是一个数组,那哈希冲突是怎么解决的呢?
实际上,我们知道通常解决哈希冲突有两种解决方式,一种是拉链法,一种是线性探测法。
前者在HashMap和ConcurrentHashMap中使用较多,而这里用到的其实就是线性探测法。
说白了就是将所有的值放在一个数组里面然后根据散列的结果到数组中取值,具体的实现方式可以看相关的数据结构知识点。

这里的关系是不是有点乱,我们来捋一下:

我们使用ThreadLocal存储的值实际是存储在Thread使用ThreadLocalMap当中的,
而这里的ThreadLocal实例值起到了一个哈希表的键的作用:

ThreadLocal

就像上图显示的那样,假如我们在线程thread1中调用了threadLocal1的get()方法,
首先会用Thread.currentThread()方法获取到thread1,然后获取到thread1的threadLocals实例,
threadLocals是一个ThreadLocalMap类型的哈希表。然后,我们再用threadLocal1作为键
来从threadLocals中获取到值Entry,并从Entry中取出存储的值并返回。

至此,我们已经了解了ThreadLocal的实现的原理,本来想看下set()方法的,但是到此已经基本真相大白了,所以也就没有继续下去的必要了。

3、总结

我们回过头来看下之前提出的几个问题:

  1. ThreadLocal中存储的值是如何保证绝对的线程安全的?
    实际上每个值都是存在线程内部的,ThreadLocal只用来帮助我们从该线程内部的哈希表中找到存放的那个值。
  2. 那么这些值是存储在什么地方?线程内部的实例字段。
  3. 是静态类型的还是实例类型的?线程内部的实例字段。
  4. 如果某个线程执行完毕了,被销毁了,那么这些存储的值会被怎么处理呢?因为是线程的局部字段,所以线程不在了,值就没有了。

以上就是ThreadLocal的用法和实现原理。


我是 WngShhng. 如果您喜欢我的文章,可以在以下平台关注我:

Java线程与ThreadLocal:深入解析Thread类源码及ThreadLocal实现原理 本文的主要目的是深入解析Java中的Thread类源码和ThreadLocal的实现原理。我们将探讨Java线程模型的核心概念,分析Thread类的关键方法和属性,并详细说明ThreadLocal的工作机制。通过这种深入的分析,我们旨在帮助读者更好地理解Java并发编程的底层原理,从而在实际开发中更有效地使用这些工具。本文将首先介绍Java线程的基本概念,然后深入分析Thread类的源码,包括其重要的方法和属性。接着,我们将详细探讨ThreadLocal的实现原理,包括其内部数据结构和工作机制。 阅读详情

相关推荐

Netapp FAS2750更换磁盘后不同步问题处理

netapp fas2750磁盘更换后不同步问题处理

jetliu05的博客 1256

threadLocal原理

一.ThreadLocal的作用   ThreadLocal提供的实际上就是一种线程隔离,不同的线程的变量归属不同的线程,线程之间不能想问访问各自的变量,当线程生命周期结束的时候,线程会被销毁。 二.ThreadLocal的原理 Thread类中有一个成员变量threadLocals: 这个ThreadLocalMap 是ThreadLocal类中一个静态内部类; ThreadLocal类中最主要的就是set 方法get方法; set方法 这个getMap(t); 传入一个Thr.

sam19911的博客 5530

NRF52832调试方法1——HardFault_Handler问题定位

一、遇到问题 keil debug模式下,直接点击全速运行(Run)发现程序卡死,点击stop按钮后,停到了HardFault_Handler位置,如下图所示。 此时使用navigate backwards(蓝色左箭头)是无效的,找不到程序卡在哪里。 二、解决办法 此时首先观察register窗口 若Stack为MSP,则复制R13(SP)的值到memory观察窗的地址搜索栏。每一行显示连续的28个地址上的存储信息,每个地址上存有一个字节。 从第21个位置起的连续四个字节是LR的值,

小梁的博客 3650

Java并发编程之ThreadLocal详解

ThreadLocal简介变量值的共享可以使用public static的形式,所有线程都使用同一个变量,如果想实现每一个线程都有自己的共享变量该如何实现呢?JDK中的ThreadLocal类正是为了解决这样的问题。ThreadLocal类并不是用来解决多线程环境下的共享变量问题,而是用来提供线程内部的共享变量,在多线程环境下,可以保证各个线程之间的变量互相隔离、相互独立。在线程中,可以通过get...

Stay Hungry, Stay Foolish 4万+

天池长期赛:二手车价格预测(422方案分享)

本次比赛是一次很好的锻炼数据挖掘能力的入门赛,从EDA-数据清洗-特征工程-模型调参-模型融合,能够完整的学习到大数据的分析和挖掘,值得历练。

weixin_46685991的博客 1万+

Procedural modeling

What is procedural modeling? One content generation option is modeling buildings, plants, clouds, cities, and worlds using an underlying system of rules. 1 Procedural Modeling: Grammars A rule-based generative system loosely organized as: ...

qq_24505417的博客 711

【并发编程】ThreadLocal详解与原理

本文讲解ThreadLocal是什么、ThreadLocal的数据结构以及ThreadLocal源码set()/get()/remove()解析,ThreadLocal使用场景,如何正确的使用ThreadLocal,ThreadLocal内存泄露原因。

小明的Java问道之路 3128

基于ESP32-C3的便携式血氧仪硬件与算法实现

血氧饱和度(SpO₂)监测是生理参数无创检测的核心技术之一,其原理基于光电容积脉搏波(PPG)信号中红光与红外光吸收比值的动态变化。该技术依赖高精度模拟前端、稳定光学激励及实时数字信号处理能力,在消费级健康设备中面临功耗、体积与测量鲁棒性的多重约束。ESP32-C3凭借集成LEDC、12位ADC与低功耗双核架构,成为PPG终端的理想主控平台;结合定制化指夹式光学探头与比率法血氧算法,可实现非诊断级但趋势可靠的日常健康监测。本文围绕硬件电路设计、电源管理策略与嵌入式信号处理流程展开,覆盖从LED驱动、跨阻放大

weixin_29025501的博客 132

java并发编程面试之ThreadLocal深度解析

ThreadLocal是Java提供的一种线程局部变量机制。它允许我们在每个线程中创建一个独立的变量副本,这个副本只能被当前线程访问和修改。ThreadLocal主要用来解决多线程环境下共享变量的并发访问问题,为每个线程提供独立的变量,从而避免了线程安全问题。

qq_33129875的博客 1061

Qemu开发ARM篇-5、buildroot制作根文件系统并挂载启动

在上一篇中,我们编译了kernel,并在qemu上进行了运行,但到最后,在挂载根文件系统时候,挂载失败,这是因为我们还没有根文件系统,在本章中,我们将制作根文件系统。rootfs制作方式有很多方式,如busyBoxbuildrootYocto等,在该篇章中,我们使用buildroot来制作根文件系统,主要考虑到busyBox制作完还需要手动首改一些启动配置比较繁琐,而Yocto如果电脑配置不是很好,编译时间过长,比较麻烦。

sinat_33909696的博客 2463

国产系统(统信 UOS )漏洞修复方式

2.1 服务器版(单漏洞更新):服务器标准版:yum upgrade-minimal --cve “CVE编号”服务器 D 版:sudo apt update&&sudo apt install “受影响的软件包”1 统信 UOS 漏洞修复方式在线升级修复桌面专业版:通过以下步骤打开在线升级:控制中心–>更新–>更新设置–>打开系统更新、安全更新。安装过程中,请勾选“我已阅读并知晓”,然后点击“开始升级”。2 点击“检查更新”–“全部下载”,如果不想进行系统更新,可以选择只下载“安全更新”。

Reyn_观极 5007

并发编程:ThreadLocal源码解析

并发编程:ThreadLocal源码解析

weixin_46619605的博客 731

光斑定位 - MATLAB实现

光斑定位是一种常见的图像处理任务,它涉及到在图像中准确定位光斑或亮点的位置。在本篇文章中,我们将使用MATLAB来实现光斑定位的算法,并提供相应的源代码。希望本文提供的MATLAB代码和步骤能够帮助您实现光斑定位任务。通过这些代码,您可以在MATLAB环境中轻松地定位光斑,并在图像上进行可视化展示。这样,我们就完成了光斑定位算法的MATLAB实现。通过以上步骤,我们可以得到一个在光斑位置上标记的图像,从而实现了光斑的准确定位。光斑定位 - MATLAB实现。

qq_39605374的博客 764

ThreadLocal实战:Java并发编程中的利器

要点 | 描述 || ThreadLocal | 用于线程隔离的利器,适用于高并发场景 || 线程安全 | 通过为每个线程绑定变量副本实现线程之间的数据隔离 || 性能 | 高吞吐量、低延迟 |ThreadLocal是Java并发编程中的利器,在高并发场景下,可以有效解决线程安全问题。随着技术的不断发展,ThreadLocal将在更多场景中得到应用。未来,我们期待看到更多关于ThreadLocal的创新和突破。

南客先生的博客 870

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

ThreadLocal原理解析

基于OpenJDK 12引本文主要想了解两个地方:ThreadLocal实例看起来是在多个线程共享,但实际上是彼此独立的,这个是怎么实现的?ThreadLocal使用不当...

勿忘初心 1894

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

并发编程之ThreadLocal

ThreadLocal是什么 是用来维护线程中的变量不被其他线程干扰而出现的一个结构,内部包含一个ThreadLocalMap类,该类为Thread类的一个局部变量,该Map存储的key为ThreadLocal对象自身,value为我们要存储的对象,这样一来,在不同线程中,持有的其实都是当前线程的变量副本,与其他线程完全隔离,以此来保证线程执行过程中不受其他线程的影响。 主要是四个方法 1. void set(Object value) 设置当前线程的线程局部变量的值。 2. public Ob...

长草颜团子 8260

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Java并发编程之ThreadLocal原理解析

1.ThreadLocal内部结构 1.1 常见误解 如果我们不去看源代码的话,可能会猜测ThreadLocal是这样子设计的: 每个ThreadLocal都创建一个Map,然后用线程作为Map的key,要存储的局部变量作为Map的value,这样就能达到各个线程的局部变量隔离的效果。这是最简单的设计方法,JDK最早期的ThreadLocal 确实是这样设计的,但现在早已不是了。 1.2 现在的设计 但是,JDK后面优化了设计方案,在JDK8中 ThreadLocal的设计是: 每个Thread维护一个T

weixin_45803046的博客 212

并发编程之ThreadLocal源码解析

ThreadLocal是什么 ThreadLocal 可以存储一个变量,该变量只有当前线程可以取出,对其它线程不可见,具有线程隔离性,在并发编程中经常会用到。 使用场景 场景一、存储当前登录用户信息 一个请示到达后端系统,系统会根据 session 或者 token 获取当前用户信息,并将该信息存储至 ThreadLocal, 在整个请示处理过程中,随时都可以从 ThreadLocal 中取出用户信息,并且不会与其它请求的用户信息混淆。 SpringSecurity 就是将用户信息构造成 SecurityC

死牛胖子的技术随笔 367

【Java并发编程】ThreadLocal(二):从设计思路到源码分析

在开始看源码之前,我们必须要知道ThreadLocal是干什么的:ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用(相同线程数据共享),也就是变量在线程间隔离(不同的线程数据隔离)而在方法或类间共享的场景。 在文章开头先解决一个问题:如何实现线程之间数据隔离? 空间换时间 思路:既然要线程隔离就不应该大家在一起,应该每个线程都有独自一块空间 为了能存多个值,应该是个数组 --> T【】 为了能指定存取,应该是Map形式 --> Entry【】 将相

A minor 1万+

深入解析ThreadLocal:从原理到实践

深入解析ThreadLocal:原理与实践 ThreadLocal是Java中实现线程局部变量的关键类,为每个线程提供独立的变量副本,解决多线程共享问题。本文从六个方面全面剖析ThreadLocal: 核心原理:通过Thread内部ThreadLocalMap实现线程隔离存储,键为ThreadLocal对象,值为变量副本 版本对比:JDK1.8优化了哈希算法和扩容策略,提升高并发性能 内存泄漏:弱引用机制下值仍为强引用,需及时调用remove()避免泄漏 最佳实践:推荐使用static final修饰,配合

私聊前往站内信:https://i.youkuaiyun.com/#/msg/chat/weixin_44976692 1094

Java 并发编程面试:volatile 与 ThreadLocal 的核心解析与实战技巧

在 Java 并发编程的面试中,volatile和ThreadLocal是两个高频考点,也是最容易让开发者混淆的概念。本文将深入解析 “volatile能保证原子性吗” 和 “ThreadLocal的内存泄漏问题” 这两个核心问题,结合实际案例剖析底层原理,并总结面试应答策略,帮助你在面试中从容应对。

Java是世界上最好的语言 858

Java并发编程——ThreadLocal

ThreadLocal详解

m0_62909831的博客 1242

Java并发编程(七)—ThreadLocal的原理及应用详解

ThreadLocal 是 Java 中的一种特殊机制,它为每个线程提供了一个独立的变量副本,主要用于解决多线程环境下的线程安全问题通过 ThreadLocal,每个线程可以拥有自己的变量副本,从而避免了线程间的数据竞争和同步问题。

echola_mendes的博客 1857

Java并发编程中ThreadLocal原理与内存泄漏问题解析

ThreadLocal是Java并发编程中非常有用的工具,它通过线程隔离解决了多线程环境下的变量共享问题。然而,不恰当的使用会导致内存泄漏问题。理解其实现原理,遵循最佳实践,合理使用remove()方法清理,才能充分发挥ThreadLocal的优势,避免潜在的风险。在复杂的应用场景中,建议结合具体框架提供的解决方案,并做好内存监控和泄漏检测。

MenzilBiz的博客 563
上一篇: Android 多线程编程:IntentService & HandlerThread
下一篇: Spring MVC 机制及其配置方式的总结
开发者如是说
博客等级 码龄10年 67粉丝 163原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值