java threadlocal 详解_Java中的ThreadLocal深入理解详解

2023-11-14

提到

ThreadLocal是什么

ThreadLocal是一个关于创建线程局部变量的类。

通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。而使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。

Global && Local

上面的两个修饰看似矛盾,实则不然。

Global 意思是在当前线程中,任何一个点都可以访问到ThreadLocal的值。

Local 意思是该线程的ThreadLocal只能被该线程访问,一般情况下其他线程访问不到。

用法简介

创建,支持泛型

ThreadLocal mStringThreadLocal = new ThreadLocal<>();

set方法

mStringThreadLocal.set("droidyue.com");

get方法

mStringThreadLocal.get();

完整的使用示例

private void testThreadLocal() {

Thread t = new Thread() {

ThreadLocal mStringThreadLocal = new ThreadLocal<>();

@Override

public void run() {

super.run();

mStringThreadLocal.set("droidyue.com");

mStringThreadLocal.get();

}

};

t.start();

}

ThreadLocal初始值

为ThreadLocal设置默认的get初始值,需要重写initialValue方法,下面是一段代码,我们将默认值修改成了线程的名字

ThreadLocal mThreadLocal = new ThreadLocal() {

@Override

protected String initialValue() {

return Thread.currentThread().getName();

}

};

Android中的应用

在Android中,Looper类就是利用了ThreadLocal的特性,保证每个线程只存在一个Looper对象。

static final ThreadLocal sThreadLocal = new ThreadLocal();

private static void prepare(boolean quitAllowed) {

if (sThreadLocal.get() != null) {

throw new RuntimeException("Only one Looper may be created per thread");

}

sThreadLocal.set(new Looper(quitAllowed));

}

如何实现

为了更好的掌握ThreadLocal,我认为了解其内部实现是很有必要的,这里我们以set方法从起始看一看ThreadLocal的实现原理。

下面是ThreadLocal的set方法,大致意思为

首先获取当前线程

利用当前线程作为句柄获取一个ThreadLocalMap的对象

如果上述ThreadLocalMap对象不为空,则设置值,否则创建这个ThreadLocalMap对象并设置值

源码如下

public void set(T value) {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null)

map.set(this, value);

else

createMap(t, value);

}

下面是一个利用Thread对象作为句柄获取ThreadLocalMap对象的代码

ThreadLocalMap getMap(Thread t) {

return t.threadLocals;

}

上面的代码获取的实际上是Thread对象的threadLocals变量,可参考下面代码

class Thread implements Runnable {

/* ThreadLocal values pertaining to this thread. This map is maintained

* by the ThreadLocal class. */

ThreadLocal.ThreadLocalMap threadLocals = null;

}

而如果一开始设置,即ThreadLocalMap对象未创建,则新建ThreadLocalMap对象,并设置初始值。

void createMap(Thread t, T firstValue) {

t.threadLocals = new ThreadLocalMap(this, firstValue);

}

总结:实际上ThreadLocal的值是放入了当前线程的一个ThreadLocalMap实例中,所以只能在本线程中访问,其他线程无法访问。

对象存放在哪里

在Java中,栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。

问:那么是不是说ThreadLocal的实例以及其值存放在栈上呢?

其实不是,因为ThreadLocal实例实际上也是被其创建的类持有(更顶端应该是被线程持有)。而ThreadLocal的值其实也是被线程实例持有。

它们都是位于堆上,只是通过一些技巧将可见性修改成了线程可见。

关于堆和栈的比较,请参考Java中的堆和栈的区别

真的只能被一个线程访问么

既然上面提到了ThreadLocal只对当前线程可见,是不是说ThreadLocal的值只能被一个线程访问呢?

使用InheritableThreadLocal可以实现多个线程访问ThreadLocal的值。

如下,我们在主线程中创建一个InheritableThreadLocal的实例,然后在子线程中得到这个InheritableThreadLocal实例设置的值。

private void testInheritableThreadLocal() {

final ThreadLocal threadLocal = new InheritableThreadLocal();

threadLocal.set("droidyue.com");

Thread t = new Thread() {

@Override

public void run() {

super.run();

Log.i(LOGTAG, "testInheritableThreadLocal =" + threadLocal.get());

}

};

t.start();

}

上面的代码输出的日志信息为

I/MainActivity( 5046): testInheritableThreadLocal =droidyue.com

使用InheritableThreadLocal可以将某个线程的ThreadLocal值在其子线程创建时传递过去。因为在线程创建过程中,有相关的处理逻辑。

//Thread.java

private void init(ThreadGroup g, Runnable target, String name,

long stackSize, AccessControlContext acc) {

//code goes here

if (parent.inheritableThreadLocals != null)

this.inheritableThreadLocals =

ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

/* Stash the specified stack size in case the VM cares */

this.stackSize = stackSize;

/* Set thread ID */

tid = nextThreadID();

}

上面代码就是在线程创建的时候,复制父线程的inheritableThreadLocals的数据。

会导致内存泄露么

有网上讨论说ThreadLocal会导致内存泄露,原因如下

首先ThreadLocal实例被线程的ThreadLocalMap实例持有,也可以看成被线程持有。

如果应用使用了线程池,那么之前的线程实例处理完之后出于复用的目的依然存活

所以,ThreadLocal设定的值被持有,导致内存泄露。

上面的逻辑是清晰的,可是ThreadLocal并不会产生内存泄露,因为ThreadLocalMap做选择key的时候,并不是直接选择ThreadLocal实例,而是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> {

/** The value associated with this ThreadLocal. */

Object value;

Entry(ThreadLocal> k, Object v) {

super(k);

value = v;

}

}

}

所以实际上从ThreadLocal设计角度来说是不会导致内存泄露的。关于弱引用,了解更多,请访问译文:理解Java中的弱引用

使用场景

实现单个线程单例以及单个线程上下文信息存储,比如交易id等

实现线程安全,非线程安全的对象使用ThreadLocal之后就会变得线程安全,因为每个线程都会有一个对应的实例

承载一些线程相关的数据,避免在方法中来回传递参数

参考文章

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

java threadlocal 详解_Java中的ThreadLocal深入理解详解 的相关文章

  • TypeScript类型注解和类型推断

    类型注解和类型推断 类型注解 let count number count 123 这段代码就是类型注解 意思是显示的告诉代码 我们的count变量就是一个数字类型 这就叫做类型注解 当你明白了类型注解的概念之后 再学类型推断就更简单了 先
  • 类的定义方法

    一 类的定义方法 注意 1 类定义最后的分号不能省略 2 类中的数据成员不能在类中进行初始化 需要在构造函数中初始化 3 类名最好能体现其功能 首字母建议大写 二 类的实现方法 1 在类定义时同时实现 若成员函数中在类中定义 则被计算机自动
  • 陀螺产业区块链第四季

    2020年4月 国家发改委在例行新闻发布会上宣布区块链被正式列为新型基础设施中的信息基础设施 自此区块链正式搭上新基建的 风口 与传统基础设施建设相比 新型基础设施建设更加侧重于突出产业转型升级的新方向 无论是5G还是区块链 都体现出加快推
  • SIFT特征提取-应用篇

    SIFT特征具有缩放 旋转特征不变性 下载了大牛的matlab版SIFT特征提取代码 解释如下 1 调用方法 将文件加入matlab目录后 在主程序中有两种操作 op1 寻找图像中的Sift特征 image descrips locs si
  • 最全iOS 应用上架流程(提交到AppStore)

    一 上架基本需求资料 1 苹果开发者账号 公司已有可以不用申请 需要开通开发者功能 每年 99 美元 2 开发好的APP 借助辅助工具appuploader创建证书跟描述文件 二 证书 描述文件 借助辅助工具appuploader 上架版本
  • django runserver开启服务(开启外网访问与ipv6访问)

    首先setting要设置 ALLOWED HOSTS 然后在启动时 使用 python manage py runserver 8000 或是 python manage py runserver 8000 这样 开启外网访问 ipv4与i
  • numpy中argsort()排序函数的使用

    argsort 函数返回的是数组从小到大的索引值 直接上例子 一 对于一维数组 1 升序排列 默认是升序 import numpy as np 一维数组升序排列 data np array 3 5 1 np argsort data 输出结
  • 数据库原理-关系模式的规范化

    关系数据库的规范化理论是数据库逻辑设计的工具 一个关系只要其分量都是不可分的数据项 它就是规范化的关系 但这只是最基本的规范化 规范化程度可以有6个不同的级别 即6个范式 规范化程度过低的关系不一定能够很好地描述现实世界 可能会存在插入异
  • 通过WIndows命令行访问MySQL数据库

    在cmd命令行里输入mysql h127 0 0 1 uroot p用户密码 这样就可以连接了 使用 show databases 这个命令可以显示出所有的database表以方便我们查看 输入 quit 退出
  • @vant/weapp

    文章目录 一 介绍 二 安装 1 cd 到项目文件目录 2 使用 npm 安装 3 修改项目配置 4 构建 5 其他文件 三 使用 四 参考 微信小程序使用 vant weapp组件 一 介绍 Vant 是一个开源的移动端组件库 在微信小程
  • 基本的tcp套接口编程

    基本的tcp套接口编程 1 socket函数 为了执行网络I O 一个进程必须做的第一件事情是调用socket函数 指定期望的通信协议类型 include
  • 基于dlib的目标追踪

    之前都在做目标检测 训练自己的检测器做检测 缺点就是电脑性能稍微差点的话 预测一次的时间就会稍久 我做的又正好是视频预测 所以连续播放都卡成PPT了 无奈之下选择抽帧检测 于是那闪烁效果堪比蹦迪现场的灯光 最后拍板定案的方法就是目标追踪了
  • 软件开发项目流程 - 立项

    引言 在互联网行业从事开发工作三年余 虽然时间不长 但对于开发流程也有一定的认识 写一篇关于这方面的内容 以记录自己的成长历程 引言 目的 立项流程 标准项目管理 总结 目的 当我们发现市场上有一个项目有利可图 且我们有能力做的时候 发起的
  • 实用的Qt窗口标志(Qt::WindowFlags)

    窗口标志枚举类型用于指定小部件的各种窗口系统属性 其中一些标志取决于底层窗口管理器是否支持它们 以下是一些比较实用的窗口标志 1 Qt Widget 这是QWidget的默认类型 如果有父窗口则为子窗口小部件 如果没有父窗口则为独立窗口小部
  • 微积分基础知识

    微积分基础知识 前言 在信息学算法竞赛中 常有些数学类问题需用到微积分 或用到微积分的算法 如母函数 HNOI2012排队 这里本人总结了一下竞赛中常用的微积分基础知识 供大家参考 有写得不好的地方请多多包涵 感谢学长帮助修改审校 若有错误
  • 技术篇之蓝牙Mesh设备是如何加入网络中

    概述 配网 Provisioning 流程属于蓝牙Mesh网络中的重要一环 正是通过配网流程 才使得蓝牙Mesh设备 Device 变成网络中的一个节点 Node 因此 本文将着重讲解配网流程及其相关概念 希望能够给读者以清晰的理解 名词解
  • SOA和伪技术

    中国的造假之风 已经成为整个国家整个社会的一个老大难问题 从最开始的假烟假酒 到后来的假名牌假新闻 从最个人化的假球迷假学历 到严重社会化的假文凭假鸡蛋 可以说是 长江后假推前假 一代新假换旧假 沉舟侧畔有千假 病树前头有十假 科学领域的造
  • 跨站脚本攻击(XSS) 漏洞原理及防御方法

    注 转载请注明出自 https blog csdn net qq 36711453 article details 83745195 XSS跨站脚本攻击 两种情况 一种通过外部输入然后直接在浏览器端触发 即反射型XSS 还有一种则是先把利用
  • react组件在页面切换时,如果页面组件已经被销毁,终止已销毁页面的请求的解决方案

    就比如说下面这个请求时间太长了 在它还没有请求成功就切换了页面 销毁了页面组件 useEffect就会给它设置成true 抛弃这个请求 const ignore useRef false useEffect gt return gt ign

随机推荐

  • 【STM32实战】机械臂快递分拣系统(二)——机械臂控制程序(上位机)编写

    STM32实战 机械臂快递分拣系统 二 机械臂控制程序 上位机 编写 前言 题目分析 蓝牙模块的使用 上位机程序的编写 连接阿里云 测试 前言 近期回校上最后一门课 刚好是做机械臂有关的题目 所以写文记录一下 主要实现的是可以自动识别获取快
  • 线与逻辑与OC门、OD门关系

    线与逻辑 两个或多个输出信号连接在一起可以实现逻辑 与 的功能 以下图为例 当与非门G1和G2输出都为1时 输出L才为1 只要有一个输出为0 则输出L为0 在硬件上 要用OC门 三极管 集电极开路 或OD门 NMOS 漏极开路 来实现 另外
  • Qt5打包——利用自带的windeployqt.exe和工具Enigma Virtual Box

    目录 运行 添加依赖 发布成单一exe形式 运行 选择Release版本 运行一次 Release 运行后会发现多了Release版本 里面有exe 但是双击时会发现缺少一些动态链接库 直接点击后缺少动态链接库 添加依赖 在你的Qt的安装包
  • 提高单机短连接QPS到20万

    提高单机短连接QPS到20万 转载于http weibo com ttarticle p show id 2309404037884855362229 一般的通讯协议在设计上都避免服务器端主动发起TCP连接关闭 让客户端来发起close s
  • 解决,worldGeo.db中有geom数据的x1表无法在QGIS中成图像

    原因 缺少geom数据对应的坐标geometry columns文件 如下图所示 STEP 1 在navicat for SQLite中将目标表x1中字段geom中blob改成 POINT 或者MULTIPOLYGON等对应的格式 注意 f
  • 成功解决Windows MemoryError: Unable to allocate 6.38 GiB for an array with shape (38

    因为运行文件所在的磁盘分配内存不够问题造成的 解决方法如下 打开我的电脑 右键属性 高级 性能设置 选择高级 更改 点击E盘 点击自定义大小 设置分配内存 我选择6G 6144kb 点击确定完成 再次运行文件 问题解决
  • invalid credential, access_token is invalid or not latest hint(微信 上传图片返回 error)

    errcode 40001 errmsg invalid credential access token is invalid or not latest hint 3G1y5a0106vr61 这种情况跟这个库没有直接关系 请检查一下是否
  • 5分钟讲解直流线性稳压降压电源基本原理

    怎么把 12 v电变为 5v呢 通过变压器是可以实现的 但是变压器只能转换交流电 那直流电怎么转换呢 我们来看下最简单的降压方式 比如负载是 5欧 那么要得到 5V的压降 按照串联分压原理 需要给它串联一个 7 欧的电阻附加 就能得到 5
  • 【LINUX相关】生成随机数(srand、/dev/random 和 /dev/urandom )

    目录 一 问题背景 二 修改方法 2 1 修改种子 2 2 使用linux中的 dev urandom 生成随机数 三 dev random 和 dev urandom 的原理 3 1 参考连接 3 2 重难点总结 3 2 1 生成随机数的
  • 9*9乘法表

    package practice 99乘法表 public class Test02 public static void main String args for int i 1 i lt 9 i 外层控制行数 for int j 1 j
  • 【查缺补漏】“.“ 和 “->“运算符的区别是什么?

    目录 简介 Note 结语 简介 Hello 非常感谢您阅读海轰的文章 倘若文中有错误的地方 欢迎您指出 昵称 海轰 标签 程序猿 C 选手 学生 简介 因C语言结识编程 随后转入计算机专业 获得过国家奖学金 有幸在竞赛中拿过一些国奖 省奖
  • shell test功能

    test测试功能 对于要测试系统上面某些文件或其相关属性时 可以使用test进行测试 test会根据相关功能返回True或False 测试文件类型test e filename 测试功能 意义 e 该文件是否存在 f 该文件名是否存在且为文
  • SSD1306 - OLED显示屏

    SSD1306 OLED显示屏 芯片介绍 引脚介绍 SSD1306是一款带控制器的用于OLED点阵图形显示系统的单片CMOS OLED PLED驱动器 它由128个SEG 列输出 和64个COM 行输出 组成 该芯片专为共阴极OLED面板设
  • 数据的无量纲化处理和标准化处理的区别是什么

    数据的无量纲化处理和标准化处理的区别是什么 请教 两者除了方法上有所不同外 在其他方面还有什么区别 解答 标准化处理方法是无量纲化处理的一种方法 除此之外 还有相对化处理方法 包括初值比处理 函数化 功效系数 方法 等等 由于标准化处理方法
  • C++11智能指针之unique_ptr

    1 智能指针概念 智能指针是基于RAII机制实现的类 模板 具有指针的行为 重载了operator 与operator gt 操作符 可以 智能 地销毁其所指对象 C 11中有unique ptr shared ptr与weak ptr等智
  • 英语 动词过去式和过去分词的变化规则

    动词过去式和过去分词有规则变化和不规则变化两种 实例顺序 动词原形过去式过去分词 发音 ed在清辅音音素后发音为 t 在浊辅音后发音为 d 在元音后发音也为 d 在 t d 后发音为 id 一 规则变化 1 一般在动词原形后加 ed loo
  • 嵌套查询及其与join的区别

    嵌套即可以写在select子句中 也可以写在from子句中 下面以SQL Entity为例来说明 1 嵌套在select中 以父表为主在select中嵌套子表信息 SELECT c Title ANYELEMENT SELECT oa Fi
  • mysql联合索引最左匹配原则的底层实现原理

    mysql联合索引最左匹配原则的底层实现原理 要看懂 需要熟悉mysql b tree的数据结构 b tree的叶节点和叶子节点的排序特性是按照 从小到大 从左到右的这么一个规则 int直接比大小 uuid比较ASCII码 联合索引的排序规
  • 极简式 Unity 获取 bilibili 直播弹幕、SC、上舰、礼物等 插件

    极简式 Unity 获取 bilibili 直播弹幕 SC 上舰 礼物等 1 声明 下载链接 软件均仅用于学习交流 请勿用于任何商业用途 2 介绍 该项目为Unity实时爬取B站直播弹幕 项目介绍 通过传入B站直播间账号 实现监控B站直播弹
  • java threadlocal 详解_Java中的ThreadLocal深入理解详解

    提到 ThreadLocal是什么 ThreadLocal是一个关于创建线程局部变量的类 通常情况下 我们创建的变量是可以被任何一个线程访问并修改的 而使用ThreadLocal创建的变量只能被当前线程访问 其他线程则无法访问和修改 Glo