ThreadLocal 详解(二)ThreadLocal的原理

news2024/12/27 11:39:38

前言:Threadlocal的原理涉及两个方面:Threadlocal实例和ThreadlocalMap;这是我画的草图

一.Threadlocal实例

        每个Threadlocal对象实际上是一个容器,用于储存线程本地的变量副本。每个线程都可以拥有自己的Threadlocal实例,这些实例可以存储不同的数据,互相之间互不影响;

public class ThreadLocal<T> {
    // 默认初始化,如果ThreadLocal没有进行初始化,进行get操作,会返回null
    protected T initialValue() {
        return null;
    }

    // 函数式初始化
    public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
        return new SuppliedThreadLocal<>(supplier);
    }
    
    
    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();
    }
    
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    
    public void remove() {
        ThreadLocalMap m = getMap(Thread.currentThread());
        if (m != null)
            m.remove(this);
    }
}

二.ThreadlocalMap

        ThreadlocalMap是Threadlocal的底层数据结构,,他是一个哈希表。每个线程都有一个与之关联的ThreadlocalMap,用于储存该线程所拥有的Threadlocal实例以及对应的值ThreadlocalMap中的的键是Threadlocal实例,值是该线程对应的Threadlocal实例的变量副本。当我们调用Threadlocal的set()方法设置时,实际上是在当前的ThreadlocalMap中以Threadlocal实例为键,将值储存在对应的位置。而调用get()方法时,则是从当前线程的ThreadlocalMap中根据Threadlocal实例获取对应的值;

三.ThreadLocal的set()方法:

 public void set(T value) {
        //1、获取当前线程
        Thread t = Thread.currentThread();
        //2、获取线程中的属性 threadLocalMap ,如果threadLocalMap 不为空,
        //则直接更新要保存的变量值,否则创建threadLocalMap,并赋值
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else{
         // 初始化thradLocalMap 并赋值
            createMap(t, value);}
           
}

从上面的代码可以看出,Threadlocal 的set()赋值的时候首先获取当前线程Thread,并且获取Thread线程中的ThreadlocalMap属性,如果Map的属性不为空,则更新当前Map的值,如果Map值为空,则将value值初始化;那么ThreadlocalMap又是什么呢?

  static class ThreadLocalMap {
 
        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;
 
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
 
    }

从源码可以看出ThreadlocalMap是Threadlocal的内部静态类,而它的构成主要是用Entry来保存数据,而且还是集成的若引用WeakReference。在Entry内部使用Threadlocal作为key,使我们设置的value作为value值;

//这个是threadlocal 的内部方法
void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
}
 
 
    //ThreadLocalMap 构造方法
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
}

四.ThreadLocal的get()方法:

public T get() {
        //1、获取当前线程
        Thread t = Thread.currentThread();
        //2、获取当前线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //3、如果map数据不为空,
        if (map != null) {
            //3.1、获取threalLocalMap中存储的值
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //如果是数据为null,则初始化,初始化的结果,TheralLocalMap中存放key值threadLocal,值为null
        return 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;
}

五.ThreadLocal的remove()方法:

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

remove()方法,直接将Threadlocal对应的值从当前Thread的ThreadMap中删除。为什么要删除,这涉及到内存泄露的问题。实际上ThreadlocalMap中使用的key为Threadlocal的弱引用,弱引用的特点是,如果这个对象是弱引用,那么在下一次GC垃圾回收的时候必然会被清理掉;所以如果是Threadlocal没有被外部强引用的情况下,在垃圾回收时候会被清理掉的,这样一来ThreadlocalMap中使用这个Threadlocal的key也会被清理掉。但是,value为强引用,不会被清理,这样一来就会出现key为null的value;Threadlocal其实是与线程绑定的一个变量,如此就会出现一个问题;如果没有将Threadlocal内的变量删除remove()或替换,它的生命周期将会与线程共存。通常线程池中对线程的管理都是采用线程复用的方法,在线程池中线程很难结束甚至永远不会结束,这将意味着线程持续时间将不可预测,甚至与JVM的生命周期一致。例如:如果Threadlocal中直接或间接包装了集合类或复杂的对象,每次在用一个Threadlocal中取出对象后,那么内部的集合类和复杂对象所占用的空间可能会开始持续膨胀;

结尾:喜欢的朋友点个赞吧!!!

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

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

相关文章

快手如何改ip地址到另外城市

在现今的数字时代&#xff0c;社交媒体平台如快手已成为我们日常生活中不可或缺的一部分。无论是分享生活点滴、观看娱乐视频&#xff0c;还是进行商业推广&#xff0c;快手都为我们提供了广阔的空间。然而&#xff0c;在使用快手的过程中&#xff0c;一些用户可能会遇到需要更…

mapbox-gl 实现房间面生成墙(借助jsts)

文章目录 一、前言二、面生成墙方法示例 一、前言 当我们从室外放大到室内展示室内图层时&#xff0c;我们可能只有房间面的数据&#xff0c;这时要展示房间墙数据&#xff0c;就需要借助工具对房间面进行缓冲&#xff0c;但是数据变动时&#xff0c;我们还要再次进行一下缓冲…

【算法专题】哈希表

哈希表是什么&#xff1f;有什么用&#xff1f;什么时候使用&#xff1f;怎么用&#xff1f; 哈希表是存储数据对的容器&#xff1b;作用在于快速查找某个元素&#xff1b;当我们需要频繁地查找元素时&#xff0c;会考虑使用哈希表&#xff1b;在算法题中&#xff0c;我们通常使…

基于el-table的表格点选和框选功能

开篇 本篇文章旨在实现一个基于el-table的表格点选和框选功能&#xff0c;除此之外&#xff0c;还支持多种模式的切换、自定义勾选日期等。且&#xff0c;该表格后续可能还会持续优化&#xff01; 功能介绍 表格点选和框选功能&#xff08;没有点击ctrl键的情况下&#xff09;…

AI安全新纪元:智能体驱动的网络安全新范式

近日&#xff0c;ISC.AI 2024第十二届互联网安全大会在北京盛大开幕。本次大会以"打造安全大模型&#xff0c;引领安全行业革命"为主题&#xff0c;旨在呼吁行业以大模型重塑安全体系&#xff0c;以保障数字经济的稳健发展。 在企业安全运营与策略实践论坛上&#x…

人工智能时代,数字化工厂如何改革?提升竞争力?

在人工智能时代&#xff0c;数字化工厂通过数据驱动的决策、智能制造、柔性生产、物联网整合以及人机协作&#xff0c;实现生产效率和产品质量的全面提升&#xff0c;并不断创新以保持竞争力。 --题记 在人工智能时代&#xff0c;数字化工厂的改革…

usb摄像头 按钮 静止按钮

usb摄像头 按钮 静止按钮 来分析一个UVC的摄像头的枚举信息 UVC学习&#xff1a;UVC中断端点介绍 https://www.eet-china.com/mp/a269529.html 输入命令lsusb -d 0c45:62f1 -v https://www.miaokee.com/705548.html >Video Class-Specific VS Video Input Header Descrip…

如何恢复未保存/删除的 WPS 文档文件

“如何恢复 WPS 文件&#xff1f;文件已损坏&#xff0c;似乎我之前没有保存过&#xff0c;软件退出&#xff0c;导致文件丢失。有什么方法可以恢复未保存的 WPS 文档吗&#xff1f;” WPS 办公套件是金山软件开发的一款很棒的套件。说实话&#xff0c;它更适合个人和办公室工…

GEE数据——全球固定宽带和移动(蜂窝)网络性能(网速)(2019-2024)

全球固定宽带和移动&#xff08;蜂窝&#xff09;网络性能 简介 全球固定宽带和移动&#xff08;蜂窝&#xff09;网络性能&#xff0c;分配给缩放级别 16 的网络 mercator 瓷砖&#xff08;赤道处约 610.8 米乘 610.8 米&#xff09;。 数据以 Shapefile 格式和 Apache Par…

在那曲,一场别开生面的盛会即将上演

当夏日的暖阳轻抚着那曲的广袤草原&#xff0c;一场展现高原之魂的盛会悄然临近。2024年8月8日&#xff0c;那曲市将举办一场独特的选美比赛——“最美牦牛”评选比赛&#xff0c;邀请各界人士、朋友共襄盛举。 牦牛&#xff0c;被誉为“高原之舟”&#xff0c;它们在这片古老的…

【nginx】解决k8s中部署nginx转发不会自动更新域名解析启动失败的问题

文章目录 1. 问题2.解决办法3.扩展说明3.1 DNS解析阶段划分3.2 问题说明3.2.1 先看/etc/resolv.conf说明3.2.2 针对第一个问题3.2.3 针对第二个问题 【后端】NginxluaOpenResty高性能实践 参考&#xff1a; https://blog.csdn.net/u010837612/article/details/123275026 1. 问…

【Java安全开发全流程解读】Ting-Write-Nuclei V1.0发布 【万户OA-SQL注入1Day-POC】

加微信即可加入WingBy交流群 不存在娱乐化 前言 nuclei-poc一键生成工具市面上很多也很全&#xff0c;比如burp插件生成POC projectdiscovery/nuclei-burp-plugin: Nuclei plugin for BurpSuite (github.com) GUI nuclei-plus/README_zh.md at main Yong-An-Dang/nuclei-p…

七夕情人节送什么礼物?看完这篇你就知道了

在这个充满爱意的时刻&#xff0c;送上一份精心挑选的礼物&#xff0c;不仅能表达你的爱意&#xff0c;更能加深彼此之间的情感联系。然而&#xff0c;选择一份合适的情人节礼物并非易事&#xff0c;因为每个人都有其独特的需求和喜好。如果你还在为情人节送什么礼物而纠结&…

1、.Net UI框架:Xamarin Forms - .Net宣传系列文章

Xamarin.Forms是一个跨平台移动应用开发框架&#xff0c;它允许开发者使用C#和.NET进行一次编码&#xff0c;然后在iOS、Android、macOS和Windows等多个平台上运行。Xamarin.Forms是Xamarin的一部分&#xff0c;而Xamarin是微软的.NET跨平台开发工具集&#xff0c;它提供了一套…

荟萃科技:海外调查问卷的核心在哪?

那就需要知道海外问卷调查是什么&#xff1f; 海外问卷调查是国外的企业为了收集消费者的意见反馈&#xff0c;在市场上发布付费问卷&#xff0c;从而进一步改善他们的产品或者服务。 我们就是回答这些付费问卷来赚取佣金。 核心来了&#xff0c;参与这些调查问卷需要有一定…

防近视台灯什么牌子好?刨析防近视台灯的详细效果

当代不管是学习还是工作&#xff0c;大家处于“卷”的状态&#xff0c;夜晚办公的上班族或是学生党都只多不少。普通的台灯只有最基础的照明作用&#xff0c;长时间下来对眼睛伤害大&#xff0c;严重还会产生眼部疾病。而在这一时刻防近视台灯——护眼灯的出现&#xff0c;成为…

ECCV2024,清华百度提出ReSyncer:可实现音频同步嘴唇动作视频生成。

清华&百度等联合提出了ReSyncer&#xff0c;可以实现更高稳定性和质量的口型同步&#xff0c;而且还支持创建虚拟表演者所必需的各种有趣属性&#xff0c;包括快速个性化微调、视频驱动的口型同步、说话风格的转换&#xff0c;甚至换脸。 ReSyncer的工作原理可以简单理解为…

暑假看这个,一个月英语水平突飞猛进

恭喜考研党们尘埃落定&#xff0c;静等9月1号入学。 闲暇之余&#xff0c;可以看看各个领域的书&#xff0c;看优秀老师的讲课视频&#xff0c;尝试学习一门新技能....不仅能学到很多知识&#xff0c;还能让生活更加丰富。 推荐几个适合大部分人提升能力的网站。 1、中国大学MO…

JVM知识总结(即时编译)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 即时编译 Java编译器经过解释执行&#xff0c;其执行速度必然会比…

【Linux】学习Linux,需要借助具象化的思维

指令与图形化界面 导读一、命令行与图形化界面二、命令行与图形化界面的发展历程1.2.1 打字机的起源1.2.2 肖尔斯和格利登型打字机1.2.3 鼠标的发明1.2.4 图形化界面&#xff08;GUI&#xff09;的发展 三、命令行与图形化之间的联系3.1 图形化界面的人机交互3.2 命令行界面的人…