ThreadLocal 源码详解

概述

ThreadLocal是一个java提供的本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不通的变量值完成操作的场景

方法

作用

public T get()

获取当前线程的副本变量值

public void set(T value)

保存当前线程的副本变量值

public void remove()

移除当前线程的副本变量值

protected T initialValue()

为当前线程初始副本变量值

ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象

底层结构

ThreadLocal是一个工具类,用来管理每个线程中的ThreadLocalMap

ThreadLocalMap就是「存储线程中产生的ThreadLocal变量以及当前线程的变量副本值的一个map表」,ThreadLocalMap是ThreadLocal中的静态内部类,并没有实现map接口,用独立的方式实现了map的功能,其内部的entry也独立实现

  • 每个Thread线程内部都有一个Map,即ThreadlLocalMap
  • Map里面存储线程本地对象(key)和线程的变量副本(value)
  • 但是,Thread内部的Map-ThreadLocalMap是由ThreadLocal维护的,由ThreadLocal负责向map获取和设置线程的变量值。所以对于不同的线程,每次获取副本值时,别的线程并不能获取到当前线程的副本值,形成了副本的隔离,互不干扰

源码解析

get()

public T get() {
        Thread t = Thread.currentThread();//获得当前线程
        ThreadLocalMap map = getMap(t);//ThreadLocalMap是ThreadLocal的一个静态类,
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);//传入的是this,this代表当前对象,即当前这个threadLocal
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();//类的私有函数,初始化数据,创建map表
    }

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;//threadLocals是Thread类中的成员变量
}

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);//创建map表并设置数据
    return value;
}
 
protected T initialValue() {
    return null;
}

流程:

    1. 获取当前线程t
    2. 根据t调用getMap()函数获取当前线程的成员变量ThreadLocalMap
    3. 判断map是否为空
      1. 不为空从map中获取线程存储的k-v entry结点,再从entry结点中获取存储的value副本并返回
      2. 为空调用setInitialValue(),创建map表并设置数据(即数据为null)

set()

public void set(T value) {
    Thread t = Thread.currentThread();//获取当前线程
    ThreadLocalMap map = getMap(t);//获取线程中的threadLocalMap
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
 
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}
 
void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

流程

    1. 获取当前线程t
    2. 根据t调用getMap()函数获取当前线程的成员变量ThreadLocalMap
      1. map非空,则将threadLocal和新的value副本放入map中
      2. map空,则对线程的成员变量ThreadLocalMap进行初始化创建,并将threadLocal和value副本放入map中

remove()

public void remove() {
 //获取线程中的成员变量threadLocalMap
 ThreadLocalMap m = getMap(Thread.currentThread());
 if (m != null)
     m.remove(this);
}
 
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

流程

也是根据当前线程获取 成员变量thredLocalMap,再移除当前对象

内存泄漏

static class Entry extends WeakReference<ThreadLocal> {
    /** The value associated with this ThreadLocal. */
    Object value;
 
    Entry(ThreadLocal k, Object v) {
        super(k);//k是弱引用
        value = v;
    }
}

Entry中的key是弱引用的,每个key都弱引用执行threadLocal,当threadLocal实例置为null以后,没有任何强引用指向threadLocal实例,所以threadLocal将会被GC回收,但是我们的value却不能回收,而这块value也不会访问到了,只有等到线程结束时value才能会回收,但是如果使用的是线程池,线程干完任务之后就会被放入池中,线程永远不会结束,就会造成内存泄漏。

在ThreadLocal中的set(),get(),remove()方法在每次操作ThreadLocalMap中的值是都会清理ThreadLocalMap中key为null的value

所以,当某个ThreadLocal变量不再使用时,记得调用remove()清理该变量。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

外卖点餐小程序平台源码系统 自由切换 轻松管理 附带源码代码包以及系统搭建教程

系统概述 外卖点餐小程序平台源码系统是一款集点餐、支付、配送、评价等功能于一体的综合性平台。该系统采用先进的互联网技术&#xff0c;支持多种支付方式&#xff0c;包括微信支付、支付宝等&#xff0c;同时支持多平台使用&#xff0c;包括微信小程序、支付宝小程序等。商…

游戏找不到steam_api64.dll如何解决,介绍5种简单有效的方法

面对“找不到steam_api64.dll&#xff0c;无法继续执行代码”的问题&#xff0c;许多游戏玩家或软件使用者可能会感到手足无措。这个错误提示意味着你的计算机系统在尝试运行某个游戏或应用程序时&#xff0c;无法定位到一个至关重要的动态链接库文件——steam_api64.dll&#…

大模型与AIGC应用相关问题 模型大型

最近经常被问&#xff0c;你看“万亿的模型都出来了&#xff0c;你们训练的千亿模型是不是落伍了&#xff1f;”我想说&#xff1a;“虽然都叫超大模型&#xff0c;但是类型是不一样的&#xff0c;虽说每一类模型训出来都不容易&#xff0c;不过澄清一下概念还是必要的”。 大…

C# WinForm —— 17 MaskedTextBox 介绍

1. 简介 本质是文本框&#xff0c;但它可以通过掩码来区分输入的正确与否&#xff0c;可以控制输入的格式、长度 主要应用场景是&#xff1a;需要格式化输入信息的情况 2. 常用属性 属性解释(Name)控件ID&#xff0c;在代码里引用的时候会用到,一般以 mtxt 开头AsciiOnly是否…

LNMP 环境下 Nginx 1.26.0 开启 HTTP/3 QUIC 支持

前几天 Nginx 1.26.0 主线版发布了&#xff0c;明月总算抽出时间更新了&#xff0c;那么自然的也要尝试一下开启 HTTP/3 QUIC 支持了&#xff0c;今天就给大家分享一下。对于我们的网站来说开启 HTTP/3 QUIC 最大的好处是页面载入速度的提升&#xff0c;尤其是在支持 HTTP/3 QU…

怎么批量下载视频?DY视频爬虫在线提取采集工具

短视频批量下载工具&#xff0c;具有多种模块和功能&#xff0c;方便用户快速批量下载短视频。该软件的详细介绍&#xff1a; 功能模块介绍&#xff1a; 一. 搜索词批量搜索下载 视频关键词添加&#xff1a;支持添加多个视频关键词进行全平台视频搜索。历史去重&#xff1a;…

以目录创建的conda环境添加到jupyter的kernel中

场景&#xff1a;由于某些原因&#xff0c;服务器上的conda环境不能通过--name的方式创建&#xff0c;只能通过指定目录即-p的方式&#xff0c;在这种情况下该环境在conda env list中没有显示&#xff0c;无法在jupyter kernel中搜到&#xff0c;只能手动添加。 1.进入环境 # …

在树莓派4b上运行OpenHarmony3.2 Release

在树莓派4b上运行OpenHarmony3.2 Release 本篇主要讲解如何将OpenHarmony3.2 Release在树莓派4b上运行起来。 硬件资源 硬件是一台树莓派4b-8G&#xff0c;sd卡容量16G。 树莓派资料请参照官网&#xff1a; https://www.raspberrypi.com/products/raspberry-pi-4-model-b/ …

安卓手机数据恢复全攻略:从备份到专业软件一网打尽!

随着科技的飞速发展&#xff0c;我们的生活中越来越离不开手机。然而&#xff0c;在使用手机的过程中&#xff0c;我们可能会遇到数据丢失的问题。对于安卓手机用户来说&#xff0c;如何有效地恢复丢失的数据是一个值得探讨的问题。本文将为您介绍安卓手机数据恢复的全攻略&…

【静态分析】软件分析课程实验A2-常量传播和Worklist求解器

Tai-e官网&#xff1a; 概述 | Tai-e 参考&#xff1a; https://www.cnblogs.com/gonghr/p/17979609 -------------------------------------------------------- 1 作业导览 为 Java 实现常量传播算法。实现一个通用的 worklist 求解器&#xff0c;并用它来解决一些数据…

部分树上问题及图的联通性(图论学习总结部分内容)

文章目录 前言三、部分树上问题及图的联通性最小生成树知识点例题 e g 1 : eg1: eg1: 走廊泼水节&#xff08;克鲁斯卡尔思想的灵活运用&#xff09; e g 2 &#xff1a; eg2&#xff1a; eg2&#xff1a; B-Picnic Planning e g 3 eg3 eg3&#xff1a;L - Classic Problem&…

无线麦克风哪个好?无线麦克风如何选择?2024高品质产品推荐整理

​在如今的数字化时代&#xff0c;无线麦克风已经逐渐渗透到我们生活的方方面面。无论是专业的自媒体人、带货主播&#xff0c;还是日常生活中的普通用户&#xff0c;无线麦克风都发挥着不可或缺的作用。而在选择无线麦克风时&#xff0c;收音降噪效果和性价比无疑是大家最为关…

Electron下复用窗口关闭、最小化和最大化按钮

在macOS下&#xff0c;创建窗口时设置&#xff1a; new BrowserWindow({titleBarStyle: hidden, // 关闭默认的titlebartrafficLightPosition: { x: 18, y: 18 }, // 交通灯距离窗口左侧和窗口上侧的像素距离 })效果&#xff1a; 在window下可以这样设置&#xff0c; new Br…

Java基于Geth1.8实现节点同步、合约部署,以及踩坑记录—主节点控制台卡死、节点同步出错的解决方案

前言&#xff1a;本文将从一个区块链入门小白的视角&#xff0c;来一步步的讲解如何实现区块链数据上链&#xff0c;链上数据查询&#xff0c;geth多节点同步。以及讲解在上链过程中&#xff0c;我踩过的坑及其解决方案。如果有不对的地方&#xff0c;还请大佬指教&#xff01;…

白酒:酒精度数对白酒贮存老熟的影响研究

云仓酒庄豪迈白酒作为一种品质的白酒&#xff0c;其酒精度数对白酒贮存老熟的影响是一个值得探讨的话题。酒精度数作为白酒的一个重要参数&#xff0c;不仅决定了酒体的基本风格&#xff0c;更在很大程度上影响了白酒在贮存过程中的变化和老熟过程。 首先&#xff0c;酒精度数的…

华为配置智能无损网络综合

配置智能无损网络综合示例 适用产品和版本 安装了P系列单板的CE16800、CE6866、CE6866K、CE8851-32CQ8DQ-P、CE8851K系列交换机V300R020C00或更高版本。 安装了SAN系列单板的CE16800、CE6860-SAN、CE8850-SAN系列交换机V300R020C10或更高版本。 CE6860-HAM、CE8850-HAM系列交换…

HR人才测评:应变能力与岗位胜任力素质测评

什么是应变能力 应变能力在职场中可以说是必备的素质之一&#xff0c;它指的是从业者需要长期活动或者是行为来迎接即将到来的挑战&#xff0c;做提前的思考&#xff0c;以适应未来的挑战&#xff0c;具有随机应变的意思。在外界还未发生变化或者是已经发生变化时&#xff0c;…

python(环境安装)搭建、pycharm安装、背景改为白色详细文章

安装python环境 1、下载python安装包 Welcome to Python.org&#xff08;官网链接&#xff09; 2、点击下载、windows、python3.12.3 安装python 执行安装程序、安装选项 选择下面两项 翻译 Use admin privieges when installing py.exe是使用administrator超级管理员用户安…

MySQL从入门到高级 --- 6.函数

文章目录 第六章&#xff1a;6.函数6.1 聚合函数6.2 数学函数6.3 字符串函数6.4 日期函数6.4.1 日期格式 6.5 控制流函数6.5.1 if逻辑判断语句6.5.2 case when语句 6.6 窗口函数6.6.1 序号函数6.6.2 开窗聚合函数6.6.3 分布函数6.6.4 前后函数6.6.5 头尾函数6.6.6 其他函数6.7 …

core.sshd.xxxxxx文件过大

背景 【紧急】【应用分组】应用: 接入点服务, 分组: 观众预发, ip: xx.xx.xx.xx 【/】&#xff0c;磁盘使用率已连续2次大于90% [当前值:100%]。报警时间: 2024-05-13 14:07:01 原因 登录机器查看&#xff0c;发现根目录下有大量的崩溃文件将 / 打满 处理 1&#xff0c; 删…