Android源码——从Looper看ThreadLocal
1 概述
ThreadLocal用于在当前线程中存储数据,由于存储的数据只能在当前线程内使用,所以自然是线程安全的。
Handler体系中,Looper只会存在一个实例,且只在当前线程使用,所以使用ThreadLocal进行存储。
2 存储原理
frameworks/base/core/java/android/os/Looper.java
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();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));
}public static @Nullable Looper myLooper() {return sThreadLocal.get();
}
Looper类中使用ThreadLocal来存储Looper对象,在调用prepare方法的时候,判断ThreadLocal对象中是否包含Looper对象,如果包含,说明重复调用了prepare,会抛异常。调用myLooper的时候就从ThreadLocal对象中获取Looper对象。
从上面可以看出ThreadLocal类似于一个容器,可以存储一个对象,通过set方法将对象存储到ThreadLocal容器中,通过get从ThreadLocal容器中获取对象。
首先看一下ThreadLocal的构造方法
public ThreadLocal() {
}
是空参构造,没有任何处理
接下来看ThreadLocal的set方法
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);
}
首先获取当前Thread对象,然后通过Thread对象获取ThreadLocalMap如果map为空,则创建Map,如果map不为空,调用set方法,则将ThreadLocal作为key,元素作为value设置到map中
java/lang/ThreadLocal.java
ThreadLocalMap getMap(Thread t) {return t.threadLocals;
}
java/lang/Thread.java
ThreadLocal.ThreadLocalMap threadLocals = null;
每一个Thread对象都持有一个ThreadLocalMap对象,如果该对象没有创建的话,就会调用set里面的createMap进行创建。
java/lang/ThreadLocal.java
void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);
}
初始化ThreadLocalMap,传入参数为ThreadLocal对象和Object对象
java/lang/ThreadLocal.java
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);
}
ThreadLocalMap存储元素采用的是Entry数组,初始容量为16,跟HashMap方式类似,采用2的指数次为数组长度进行hash。
ThreadLocalMap的set方法
private void set(ThreadLocal<?> key, Object value) {// We don't use a fast path as with get() because it is at// least as common to use set() to create new entries as// it is to replace existing ones, in which case, a fast// path would fail more often than not.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)]) {// Android-changed: Use refersTo() (twice).// ThreadLocal<?> k = e.get();// if (k == key) { ... } if (k == null) { ... }if (e.refersTo(key)) {e.value = value;return;}if (e.refersTo(null)) {replaceStaleEntry(key, value, i);return;}}tab[i] = new Entry(key, value);int sz = ++size;if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash();
}
采用hash算法,使用ThreadLocal对象作为Key计算索引,并存入value。
ThreadLocal的get方法
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();
}
首先获取Thread对象,然后获取Thread对象中的ThreadLocalMap对象,然后调用getEntry获取Entry对象,并返回其value。
private Entry getEntry(ThreadLocal<?> key) {int i = key.threadLocalHashCode & (table.length - 1);Entry e = table[i];// Android-changed: Use refersTo().if (e != null && e.refersTo(key))return e;elsereturn getEntryAfterMiss(key, i, e);
}
也是通过hash算法算出索引后返回Entry对象
3 总结
- ThreadLocal用于存储线程私有数据,一个ThreadLocal对象可以存储一个数据
- ThreadLocal实现线程私有是因为存储数据时,存储到Thread类中持有的ThreadLocalMap对象中的Entry数组中,采用哈希算法进行存储,key为ThreadLocal对象,value为T类型
- 由于不同的线程存储到的就是不同的Thread类的ThreadLocalMap中,所以各个线程的ThreadLocalMap独立,自然存储其中的ThreadLocal就是独立的
- 同一个线程中多个ThreadLocal存储多个数据,但存入的是同一个Thread对象的同一个ThreadLocalMap对象中,所以一个线程对应一个Thread对象,对应同一个ThreadLocalMap对象,可以存储多个ThreadLocal数据
相关文章:
Android源码——从Looper看ThreadLocal
1 概述 ThreadLocal用于在当前线程中存储数据,由于存储的数据只能在当前线程内使用,所以自然是线程安全的。 Handler体系中,Looper只会存在一个实例,且只在当前线程使用,所以使用ThreadLocal进行存储。 2 存储原理 …...
16、Flink 的table api与sql之连接外部系统: 读写外部系统的连接器和格式以及JDBC示例(4)
Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…...
MySQL 自定义 split 存储过程
MySQL 没有提供 split 函数,但可以自己建立一个存储过程,将具有固定分隔符的字符串转成多行。之所以不能使用自定义函数实现此功能,是因为 MySQL 的自定义函数自能返回标量值,不能返回多行结果集。 MySQL 8: drop pr…...
专题-【十字链表】
有向图的十字链表表示法:...
微信小程序教学系列(2)
第二章:小程序开发基础 1. 小程序页面布局与样式 在小程序开发中,我们可以使用 WXML(WeiXin Markup Language)和 WXSS(WeiXin Style Sheet)来定义页面的布局和样式。 1.1 WXML基础 WXML 是一种类似于 H…...
社科院与美国杜兰大学金融管理硕士项目——畅游于金融世界
随着社会经济的不断发展,职场竞争愈发激烈,很多同学都打算通过报考研究生来实现深造,提升自己的综合能力和竞争优势,获得优质的证书。而对于金融专业的学生和在职人员来说,社科院与美国杜兰大学金融管理硕士项目是一个…...
功能强大、超低功耗的STM32WL55JCI7、STM32WL55CCU7、STM32WL55CCU6 32位无线远距离MCU
STM32WL55xx 32位无线远距离MCU嵌入了功能强大、超低功耗、符合LPWAN标准的无线电解决方案,可提供LoRa、(G)FSK、(G)MSK和BPSK等各种调制。STM32WL55xx无线MCU的功耗超低,基于高性能Arm Cortex-M4 32位RISC内核(工作频率高达48MHz)…...
【自适应稀疏度量方法和RQAM】疏度测量、RQAM特征、AWSPT和基于AWSPT的稀疏度测量研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
sql递归查询
一、postgresql 递归sql with recursive p as(select t1.* from t_org_test t1 where t1.id2union allselect t2.*from t_org_test t2 join p on t2.parent_idp.id) select id,name,parent_id from p; sql中with xxxx as () 是对一个查询子句做别名,同时数据库会对…...
常见前端面试之VUE面试题汇总三
7. Vue 中封装的数组方法有哪些,其如何实现页面更新 在 Vue 中,对响应式处理利用的是 Object.defineProperty 对数据进 行拦截,而这个方法并不能监听到数组内部变化,数组长度变化,数 组的截取变化等,所以需…...
Three.js 实现模型材质分解,拆分,拆解效果
原理:通过修改模型材质的 x,y,z 轴坐标 positon.set( x,y,z) 来实现拆解,分解的效果。 注意:支持模型材质position 修改的材质类型为 type“Mesh” ,其他类型的材质修改了position 可能没有实际效果 在上一篇 Three.js加载外部glb,fbx,gltf…...
《JVM修仙之路》初入JVM世界
《JVM修仙之路》初入JVM世界 博主目前正在学习JVM的相关知识,想以一种不同的方式记录下,娱乐一下 清晨,你睁开双眼,看到刺眼的阳光,你第一反应就是完了完了,又要迟到了。刚准备起床穿衣的你突然意识到不对&…...
苍穹外卖 day1 搭建成功环境
引入 idea找不到打包生成的文件目录怎么办,首先点击这个小齿轮 show ecluded files然后就能找到隐藏的文件 这个jar包内含tomcat,可以直接丢在linux上用 开发环境:开发人员在开发阶段使用的环境,一般外部用户无法访问 测试环…...
智能主体按照功能划分
(1) 构件接口主体 构件接口主体提供构件与用户之间的接口。当一个用户通过代理主体向 元组空间提出申请,并找到相匹配的构件主体时,此构件主体会将其所在构件主体 组中的构件接口主体通过申请用户的代理主体传送到用户的界面。 (2) 构件主体 通过构…...
python中的matplotlib画折线图(数据分析与可视化)
先导包(必须安装了numpy 、pandas 和matplotlib才能导包): import numpy as np import pandas as pd import matplotlib.pyplot as plt核心代码: import numpy as np import pandas as pd import matplotlib.pyplot as pltpd.se…...
大数据数据仓库
一.在线教育 1.数据采集 1.数仓概念 数据仓库是为企业制定决策,提供数据支持的。数据采集和存储、对数据进行计算和分析 2.项目架构 2.数据分类 业务数据 用户行为数据 爬虫数据 2.离线数仓 3.实时数仓...
Java“牵手“速卖通商品详情页面数据获取方法,速卖通API实现批量商品数据抓取示例
速卖通商城是一个网上购物平台,售卖各类商品,包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取速卖通商品详情数据,您可以通过开放平台的接口或者直接访问速卖通商城的网页来获取商品详情信息。以下是两种常用方法的介绍:…...
【Git】代码误推送还原(真实项目环境,非纸上谈兵)
背景 RT, 我今天眼睛花了,不小心把工作分支【合并】到了一个不相干的功能分支上,并且代码已经推送到远程仓库了。于是,只能尝试还原到上一次提交中。 【合并】分支有一个点我们是不可避免的,文字很难描述,…...
CPU 飙升?这3大场景助你精准定位
1 常用的 Load 分析方法 CPU高、Load高 通过 top 命令查找占用CPU最高的进程PID; 通过top -Hp PID查找占用CPU最高的线程TID; 对于java程序,使用jstack打印线程堆栈信息; 通过printf %x tid打印出最消耗CPU线程的十六进制; …...
6、Spring_Junit与JdbcTemplate整合
Spring 整合 1.Spring 整合 Junit 1.1新建项目结构 1.2导入依赖 导入 junit 与 Spring 依赖 <!-- 添加 spring 依赖--> <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权
摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题:安全。文章将详细阐述认证(Authentication) 与授权(Authorization的核心概念,对比传统 Session-Cookie 与现代 JWT(JS…...
ArcGIS Pro+ArcGIS给你的地图加上北回归线!
今天来看ArcGIS Pro和ArcGIS中如何给制作的中国地图或者其他大范围地图加上北回归线。 我们将在ArcGIS Pro和ArcGIS中一同介绍。 1 ArcGIS Pro中设置北回归线 1、在ArcGIS Pro中初步设置好经纬格网等,设置经线、纬线都以10间隔显示。 2、需要插入背会归线…...
边缘计算网关提升水产养殖尾水处理的远程运维效率
一、项目背景 随着水产养殖行业的快速发展,养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下,而且难以实现精准监控和管理。为了提升尾水处理的效果和效率,同时降低人力成本,某大型水产养殖企业决定…...
