ThreadLocal学习

2023-11-19

1、threadLocal图解

  java.lang.ThreadLocal类实现了线程的本地存储。

ThreadLocal的内部实现:

  • ThreadLocal的内部实现包括一个类似HashMap的对象,这里称之ThreadLocalMap。

  • ThreadLocalMap的key会持有对ThreadLocal实例的弱引用(Weak Reference),value会引用具体存储的对象实例。

【强引用】:

1、threalLocal对象指向threalLocalMap中的key .

2、线程对象 指向 堆中的 threalLocalMap。

【弱引用】:

1、threalLocalMap 的key为 threadLocal对象,即threadLocal对象 指向key为弱引用。

部分源码如下: 

// ThreadLocal类中的get()方法: 
	// 代码逻辑:
	// 1、通过当前线程对象,获取线程对象中的成员变量threadLocals 即threadLocalMap。
	// 2、拿到threadLocalMap后,根据当前threadLocal对象作为key,获取value值。
	// 3、如果threadLocalMap为空,进行初始化
	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();
    }

	// ThreadLocal类中的setInitialValue()方法: 设置ThreadLocalMap的初始化值。
	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类中的initialValue()方法:ThreadLocalMap初始value为null
	protected T initialValue() {
        return null;
    }
	// ThreadLocal类中的createMap方法: 初始化ThreadLocalMap,即线程的threadLocals对象初始化。
	void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
	
	// ThreadLocalMap类的构造方法:存储用的是Entry数组。Entry的key为ThreadLocal对象。
	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类中的getMap方法:
	ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
	// ThreadLocal类中的remove方法:
	public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }
	// ThreadLocalMap类中的remove方法:
	private void remove(ThreadLocal<?> key) {
        Entry[] tab = table;
        int len = tab.length;
        int i = key.threadLocalHashCode & (len-1);
        for (Entry e = tab[i];
             e != null;
             e = tab[i = nextIndex(i, len)]) {
            if (e.get() == key) {
                e.clear();
                expungeStaleEntry(i);
                return;
            }
        }
    }

	// Thread类中的成员变量threadLocal即: 线程中的ThreadLocalMap
	ThreadLocal.ThreadLocalMap threadLocals = null;

 2、ThreadLocal原理

  • Thread类中一个成员变量,ThreadLocal.ThreadLocalMap threadLocals

  • ThreadLocal本身不存储数据,像是一个工具类,基于ThreadLocal去操作ThreadLocalMap

  • ThreadLocalMap本身就是基于Entrty[]实现的,因为一个线程被可以绑定多个ThreadLocalMap,这样一来,可能需要存储多个数据,所以采用Entrty[]的形式实现。

  • 每一个线程有自己独立的ThreadLocalMap, 再基于ThreadLocald对象本身作为key,对value进行存取。

  • ThreadLocalMap的key是一个弱引用。弱引用的特点:即便对象有弱引用,在GC时,也必须被回收。如果ThreadLocal对象为局部变量,即方法执行结束后,threadLocal对象强引用消失,如果key的引用是强引用,会导致threadLocal对象无法被回收如果threadLocal是静态成员变量,则不会存在这个问题

ThreadLocal内存泄露问题:

  • 如果threadLocal对象的引用丢失即:使用的threadLocal不是静态成员变量,而是局部变量),key因为弱引用被GC回收掉,如果同时线程还没有被回收,就会导致内存泄露,内存中的value无法被回收,同时也无法被获取到。

  • 解决方法:只需要在使用完毕threadLocal对象之后,及时的调用threadLocal.remove()方法,移除该threalLocal对象key的Entry即可。(说明:threadLocal.remove()是threadLocal对象的强引用,即在移除Entry前,threalLocal对象不会失效)

总结:

  • 线程中threadLocalMap(即threadLocals),是在第一次调用ThreadLocal的get或set方法时,才会创建。

  • 线程调用很深,但又不想传参时,可以使用threadLocals

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ThreadLocal学习 的相关文章

  • dubbo分布式服务

    架构 节点角色说明 Provider 暴露服务的服务提供方 Consumer 调用远程服务的服务消费方 Registry 服务注册与发现的注册中心 Monitor 统计服务的调用次调和调用时间的监控中心 Container 服务运行容器 调
  • Linux磁盘管理命令大全

    1 cd命令 Linux cd命令用于切换当前工作目录至 dirName 目录参数 其中 dirName 表示法可为绝对路径或相对路径 若目录名称省略 则变换至使用者的 home 目录 也就是刚 login 时所在的目录 另外 也表示为 h
  • RedHat7.2系统中安装snmp工具并配置服务

    简单介绍 snmpwalk是SNMP的一个工具 用户可以通过snmpwalk查看支持SNMP协议设备的一些信息 比如IP地址 内存使用率等 snmpwalk是一款比较好用的采集系统信息的工具 安装snmp工具 输入以下指令安装软件包 以普通
  • 常用的 Druid 参数

    Druid 参数 连接池初始化大小 最大连接数 最小空闲连接数这几个连接数有什么作用 他们的关系是怎么样的 初始连接数如果都被占用了 连接池会创建最小空闲数个连接吗 官网 Druid Database for modern analytic
  • 机器学习技术(八)——朴素贝叶斯算法实操

    机器学习技术 八 朴素贝叶斯算法实操 文章目录 机器学习技术 八 朴素贝叶斯算法实操 一 引言 二 导入相关依赖库 三 读取并查看数据 四 数据预处理 五 构建两种模型进行比较 1 只考虑Dayofweek以及District 2 加入犯罪

随机推荐

  • 高校校园网建设方案【含网络拓扑图+拓扑结构图+配置命令】(详细版)

    xxx大学xxx校区网络整体规划设计方案 目 录 一 项目综述 1 1 1学校概况 1 1 1 1 1 1 2建设目标 1 1 2 1 概述 1 1 2 2 具体目标 1 1 3建设原则 1 1 3 1 概述 1 1 3 2 具体原则 2
  • Ubuntu20.04安装g3log、glog和gflags

    建议最好先安装最新版本的cmake 在进行以下安装 cmake安装教程 1 安装gflags 方法一 首先打开终端 git clone https github com gflags gflags git cd gflags mkdir b
  • C++ Pat甲级1011 World Cup Betting (20 分)

    1011 World Cup Betting 20 分 With the 2010 FIFA World Cup running football fans the world over were becoming increasingly
  • 常见的常微分方程的一般解法

    本文归纳常见的常微分方程的一般解法 如果没有出现意外 本文将不包含解法的推导过程 常微分方程 我们一般可以将其归纳为如下n类 可分离变量的微分方程 一阶 一阶齐次 非齐次 线性微分方程 一阶 包含伯努利 二阶常系数微分方程 二阶 高阶常系数
  • kafka如何保证数据可靠性和数据一致性

    数据可靠性 Kafka 作为一个商业级消息中间件 消息可靠性的重要性可想而知 本文从 Producter 往 Broker 发送消息 Topic 分区副本以及 Leader 选举几个角度介绍数据的可靠性 Producer 往 Broker
  • SIFT和SURF的替换算法——ORB (Oriented FAST and Rotated BRIEF 快速定向和旋转)

    SIFT和SURF的替代算法 ORB Oriented FAST and Rotated BRIEF 快速定向和旋转 1 效果图 2 源码 参考 1 用于关键点检测和描述的SIFT Scale Invariant Feature Trans
  • Faster R-CNN系列之MATLAB篇

    我发现 我是个懒人 不对 我一直是个懒人 但是 电光火石间 不知怎么地 我决定 我写个博客吧 我是废话的分割线 最开始接触Faster R CNN 先尝试跑的其实是PYTHON版 但是编译过程中出错了 我又从来没接触过python 自己稍稍
  • 【INS-30014】无法检查指定的位置是否位于CFS上的解决办法

    安装oracle数据库过程中 出现 INS 30014 无法检查指定的位置是否位于CFS上的解决办法如下 安装过程中 选择 仅安装数据库软件 在安装成功后 使用DBCA工具创建以及配置数据库即可
  • Oracle:数据库设计三大范式

    数据库设计三大范式 为什么要谈及范式 这也是为了数据库设计做准备 对于表设计而言 我们需求何种程度的设计 这完全取决你数据的规模 好比你建房子 要是建个一两层 基本上不需要什么设计 直接开工就行 要是建个这样的房子还找设计公司的话 这无疑是
  • 安装win7后怎么装linux系统,小编教你如何使用u盘安装Linux系统

    第二步 u盘安装Linux 1 U盘插到要安装Linux的电脑上后 启动电脑 在启动时 一直按F2键 就能进入到主板的BIOS控制界面 按左右键移动到boot选项 然后按上下键到removeable device选项 再按 号移动它的位置在
  • flutter城市选择页面

    import dart convert import package test http DioManager dart import package test http api life api dart import package t
  • [分布式] zookeeper集群与kafka集群

    目录 一 Zookeeper 概述 1 1 Zookeeper定义 1 2 Zookeeper 工作机制 1 3 Zookeeper 特点 1 4 Zookeeper 数据结构 1 5 Zookeeper 应用场景 1 6 Zookeepe
  • 小程序跳转小程序

    小程序如何跳转到其他小程序 微信小程序跳转到其他小程序有两种方式 一种是用组件navigator跳转
  • python简单的预测模型_如何使用 Python 或 matlab 实现一个简单根据年份预测年龄的模型...

    Escapist367 110 天前 import torch inputs outputs for year1 in range 1900 2020 for year2 in range 1900 2020 for age1 in ran
  • OD机试题目【计算网络信号】

    网络信号经过传递会逐层衰减 且遇到阻隔物无法直接穿透 在此情况下需要计算某个位置的网络信号值 注意 网络信号可以绕过阻隔物 array m n 的二维数组代表网格地图 array i j 0代表i行j列是空旷位置 array i j x x
  • devops理念

    一 开发模式 传统开发模式 也就是瀑布型开发 瀑布模型式是最典型的预见性的方法 严格遵循预先计划的需求 分析 设计 编码 测试的步骤顺序进行 例如需求规格 设计文档 测试计划和代码审阅等等 其中需求分析占比很重 对客户想要的产品进行详细分析
  • android jni 报错 libjnidispatch.so 找不到

    Caused by java lang UnsatisfiedLinkError Native library com sun jna android arm libjnidispatch so not found in resource
  • ffmpeg by id和by name查找decoder的区别

    转自 https blog csdn net muyuyuzhong article details 79735763 同一个 AVCodecID 可能对应多个不同的编解码器 AVCodec 他们有不同的 AVCodec name avco
  • 一张图深度解析Linux共享内存的内核实现

    一张图深度解析Linux共享内存的内核实现 Sailor forever sailing 9806 163 com http blog csdn net sailor 8318 article details 39484747 PDF版本下
  • ThreadLocal学习

    1 threadLocal图解 java lang ThreadLocal类实现了线程的本地存储 ThreadLocal的内部实现 ThreadLocal的内部实现包括一个类似HashMap的对象 这里称之ThreadLocalMap Th