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代表当前对象,即当前这个threadLocalif (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);elsecreateMap(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);//获取线程中的threadLocalMapif (map != null)map.set(this, value);elsecreateMap(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() {//获取线程中的成员变量threadLocalMapThreadLocalMap 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()清理该变量。

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

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

相关文章

PSFR-GAN复现

写在前面&#xff1a;本博客仅作记录学习之用&#xff0c;部分图片来自网络&#xff0c;如需引用请注明出处&#xff0c;同时如有侵犯您的权益&#xff0c;请联系删除&#xff01; 文章目录 前言快速开始安装依赖权重下载及复原 训练网络数据集训练脚本 代码详解训练BaseOptio…

NSSCTF | [SWPUCTF 2021 新生赛]caidao

打开题目&#xff0c;只有一个图片&#xff0c;图片中间是一个一句话木马的一部分&#xff0c;意思是服务器可以执行通过POST的请求方式传入参数为wllm的命令&#xff0c;那这就是典型的命令执行&#xff0c;当然&#xff0c;也可以使用蚁剑或者菜刀连接这个木马 一句话木马的…

DOM API

DOM 基本概念 DOM 全称为 Document Object Model&#xff0c;就是文档对象模型。html 的每个标签都可以映射到 js 中的一个对应对象上。 DOM 树 一个页面的结构是一个树形结构, 称为 DOM 树 . 树形结构在数据结构阶段会介绍. 就可以简单理解成类似于 " 家谱 &q…

Qt正则表达式运用---QRegExp

文章目录 1.匹配数字1.1个位数1.2两位数 及多位数1.3 匹配非数字 匹配单词 1.匹配数字 1.1个位数 QString str "0 1 2 23 10 20 &#xffe5;24 #0 44 111 22- 123 58 99 ";QRegExp rx("\\b\\d{1}\\b");int index0;while(rx.indexIn(str,index) ! -1){…

全场景智能终端RK3288主板在智能垃圾回收项目的应用,支持鸿蒙,支持全国产化

全场景智能终端主板AIoT-3588A推出的智能化垃圾回收项目&#xff0c;旨在解决城市化进程中日益突出的垃圾处理问题。智能垃圾分类箱具备触屏操作、自动称重、分类投放以及电子语音播报提示等多项功能&#xff0c;居民能够经过分类积分卡、手机扫码、人脸识别等多种途径进行投放…

【小笔记】streamlit使用笔记

【小笔记】streamlit使用笔记 1.streamlit是什么&#xff0c;为什么要用它&#xff1f; 一句话&#xff0c;这个东西是一个python的可视化库&#xff0c;当你想要给你的程序添加个web界面&#xff0c;而又不会或不想用前端技术时&#xff0c;你就可以考虑用它。 类似的可视化库…

uni-app(四):原生插件开发(Android)

原生插件开发 原生插件开发module1.创建模块2.解决报错3.修改依赖4.编写插件代码5.添加插件配置6.引入模块7.调用插件代码8.运行 component1.创建模块2.解决报错3.修改依赖4.编写插件代码5.添加插件配置6.引入模块7.调用插件代码8.运行 原生插件开发 主要分为两类扩展: Module:…

1378:最短路径(shopth)

【解题思路】 本题图中可能存在负权边&#xff0c;因此不能用dijkstra算法。可以使用spfa算法。本题顶点数最大为80&#xff0c;可以使用复杂度为O(V^3)的floyd算法。输入处理&#xff1a;使用scanf来输入。如果正确输入一个数字&#xff0c;scanf返回1。如果遇到’-&#xff…

EfficientNet网络结构详细解读+SE注意力机制+pytorch框架复现

文章目录 &#x1f680;&#x1f680;&#x1f680;前言一、1️⃣ 网络详细结构1.1 &#x1f393; MBConv结构1.2 ✨SE注意力机制模块1.3 ⭐️Depthwise Separable Convolution深度可分离卷积1.3.1 普通卷积操作(Convolution)1.3.2 逐深度卷积&#xff08;Depthwise Convoluti…

西班牙怎么注册公司呢

西班牙&#xff0c;是位于欧洲西南部的君主立宪制国家&#xff0c;与葡萄牙同处于伊比利亚半岛&#xff0c;东北部与法国及安道尔接壤。西班牙的制造业、旅游业发达。西班牙是世界最大的造船国之一&#xff0c;也是最大的汽车生产国之一。西班牙鼓励外商投资&#xff0c;对小微…

C++单例模式(三种方式)

单例模式实现要点&#xff1a; 构造函数私有化 - 为避免其他程序过多建立该类对象&#xff0c;先禁止其他程序建立该类对象类中创建一个本类对象 - 本类中自定义对象&#xff0c;让其他程序可以访问提供方法获取到该对象 - 方便其他程序对自定义对象的访问 单例模式实现方式&a…

Java并发编程——相关基础概念

Java并发编程是Java中处理多个任务同时执行的能力。在构建高性能、可扩展和响应性良好的系统时&#xff0c;并发编程是非常关键的。以下是Java并发编程中的一些基础概念&#xff1a; 线程&#xff08;Thread&#xff09;&#xff1a; 线程是操作系统调度的最小单位&#xff0c;…

【强训笔记】day21

NO.1 思路&#xff1a;第一个位置放最小的&#xff0c;其次放最大的&#xff0c;依次类推。 代码实现&#xff1a; #include<iostream>using namespace std; int n;int main() {cin>>n;int left1,rightn;while(left<right){cout<<left<<" &…

Nios-II编程

文章目录 一硬件部分设计1Qsys2Quartus 二软件1Nios-II Eclipse 三运行项目及效果1配置 FPGA 一硬件部分设计 1Qsys 1创建一个项目 2点击 Tools 下拉菜单下的 Platform Designer 工具&#xff0c;启动 Platform Designer 后&#xff0c;点击 File-save&#xff0c;在文件名中…

2024年华为OD机试真题- 求字符串中所有整数的最小和-Java-OD统一考试(C卷D卷)

题目描述: 输入字符串s,输出s中包含所有整数的最小和 说明 1. 字符串s,只包含 a-z A-Z +- ; 2. 合法的整数包括 1) 正整数 一个或者多个0-9组成,如 0 2 3 002 102 2)负整数 负号 - 开头,数字部分由一个或者多个0-9组成,如 -0 -012 -23 -00023 输入描述: 包含…

云原生基础设施和操作系统分论坛 03-在Kubernetes上运行Apache Spark进行大规模数据处理的实践【数据分析】

https://spark.apache.org/视频观看&#xff1a;https://www.bilibili.com/video/BV17J4m1n7Gv/?spm_id_from333.999.0.0 简介 Apache Spark 是专为大规模数据处理而设计的快速通用的计算引擎。Spark是UC Berkeley AMP lab (加州大学伯克利分校的AMP实验室)所开源的类Hadoop…

SpringBoot项目中基于PDF模板生成PDF文档

&#x1f341; 作者&#xff1a;知识浅谈&#xff0c;CSDN签约讲师&#xff0c;CSDN博客专家&#xff0c;华为云云享专家&#xff0c;阿里云专家博主 &#x1f4cc; 擅长领域&#xff1a;全栈工程师、爬虫、ACM算法 &#x1f492; 公众号&#xff1a;知识浅谈 &#x1f525; 微…

kong 网关 docker 安装3.4

kong 安装 docker network create kong-net安装postgres 9.6 本版很重要 高版本 安装konga 初始化会有问题 docker run -d --name kong-database \--network=kong-net \-p 5432:5432 \-e "POSTGRES_USER=kong" \-e "POSTGRES_DB=kong" \-e "POSTGRE…

uniapp push个推在线和离线消息监听,离线消息intent参数设置和获取,java后端推送

uniapp push 1.0版本 我用华为手机测试的离线消息&#xff0c;首先要保证在华为后台推送消息&#xff0c;uniapp离线打包的app能收到。 java后端推送 pom.xml依赖 <dependency><groupId>com.getui.push</groupId><artifactId>restful-sdk</artifac…

Java入门基础学习笔记20——三元运算符、运算符优先级

1、三元运算符介绍&#xff1a; 格式&#xff1a; 条件表达式 ? 值1: 值2 执行流程&#xff1a;首先计算关系表达式的值&#xff0c;如果值为true&#xff0c;就返回值1&#xff0c;如果值为false&#xff0c;就返回值2。 例1&#xff1a; package cn.ensource.operator;p…