Android Handler 机制(五):ThreadLocal的工作原理

Handler消息机制和ThreadLocal原理 一、简介 Handler作为Android线程间通信的常用方式,主要由Handler、Looper、MessageQueue、message四个部分组成 , Handler负责线程间消息通讯的发送消息和接收处理消息 Looper用于从MessageQueue中轮询获得Message MessageQueue则是一个单线链表的用于存储Message的数据结构 Message则是线程间通信的载体 总体流程图如下 简单使用,如下子线程发送message,主线程更新UI private Handler han 阅读详情

一、Handler机制与ThreadLocal

在Handler机制的时候,我们会接触到Looper中的一个很重要的类:ThreadLocal,ThreadLocal并不是线程,它的作用是可以在每个线程中存储数据。

Handler在创建的时候就会获取当前线程的Looper来构造消息循环系统,获取的方式就是通过ThreadLocal。ThreadLocal可以在不同的线程中互补干扰的存储并提供数据,Handler就是通过ThreadLocal可以轻松获取每个线程的Looper。当然需要注意的是,线程是默认没有Looper的,如果需要使用Handler就必须为线程创建Looper。

大家经常提到的主线程,也叫UI线程,它就是ActivityThread,ActivityThread被创建时就会初始化Looper,这也是在主线程中默认可以使用Handler的原因。

二、ThreadLocal 基本使用

ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有指定线程中可以获取到存储的数据,对于其它线程来说无法获取到数据。一般开发情景中我们用不到ThreadLocal,但是在一些非常复杂或者特殊的情景中, 通过ThreadLocal可以轻松地实现一些看起来很复杂的功能。

在Android的系统机制中,以下源码中使用到了ThreadLocal:

  • Looper
  • ActivityThread
  • ActivityManagerService

具体到ThreadLocal的使用场景,一般可以概况为,当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。

下面是使用ThreadLocal的最简单的例子:

public class ThreadLocalTest {

    static ThreadLocal threadLocal = new ThreadLocal();

    public static void main(String[] args) {
        threadLocal.set(true);
        System.out.println("Main ThreadLocal Value = " + threadLocal.get());
        new Thread(new Runnable() {
            @Override
            public void run() {
                threadLocal.set(false);
                System.out.println("ThreadLocal_1 Value = " + threadLocal.get());
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("ThreadLocal_2 Value = " + threadLocal.get());
            }
        }).start();
    }
}

输出的结果如下:

Main ThreadLocal Value = true
ThreadLocal_1 Value = false
ThreadLocal_2 Value = null
可以看出,虽然在不同线程中访问的是同一个ThreadLocal对象,但是它们通过ThreadLocal来获取到的值却是不一样的,这就是ThreadLocal的奇妙之处。

三、ThreadLocal源码

View Code
ThreadLocal 暴露了5个基本的操作和构造方法,主要的功能有:构造方法、设值方法、取值方法和资源回收;

1. 构造方法

ThreadLocal 是一个泛型类,只提供了一个构造方法,通过泛型可以指定要存储的值的类型;这个构造方法通常可以单独使用,也可以配合initialValue方法在实例化对象时提供一个初始值。

2.设值方法set

保存数据可以使用set方法,多次调用set方法不会保存多个数据,而是会覆盖掉。一个ThreadLocal只能保存一个数据:

public void set(T value) {
    Thread t = Thread.currentThread();  // 获取当前线程
    ThreadLocalMap map = getMap(t); // 拿到当前线程中的ThreadLocalMap
    if (map != null)
        map.set(this, value);  // 线程中存在ThreadLocalMap,设值
    else
        createMap(t, value);   // 线程中不存在ThreadLocalMap,创建后再设值
}

3.取值方法get

在没有使用set方法设值之前,调用get方法获取到的值将是initialValue方法设置的值(如果此方法未被覆盖则返回null)。调用set方法设值之后,返回的就是设置的值。

public T get() {
        Thread t = Thread.currentThread(); // 获取当前线程
        ThreadLocalMap map = getMap(t); // 拿到当前线程保存的ThreadLocalMap
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this); // 这里传入的this就是当前的ThreadLocal对象,拿到ThreadLocal对应的值
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value; // 拿到ThreadLocal的值
                return result;
            }
        }
        return setInitialValue(); // 调用setInitialValue方法返回初始值
    }

4.资源回收remove

当我们不再需要保存的数据时,应该通过remove方法将当前线程中保存的值移除掉使对象得到GC(调用remove方法将把ThreadLocal对象从当前线程的ThreadLocalMap移除):

public void remove() {
     ThreadLocalMap m = getMap(Thread.currentThread()); // 拿到当前线程中的ThreadLocalMap
     if (m != null) {
        m.remove(this); // 从ThreadLocalMap移除key为当前ThreadLocal对象的记录
     }
}

调用remove方法会清空使用set方法设置的值,此时如果再次调用了get方法,由于ThreadLocal对应的记录已经不存在,所以将会执行return setInitialValue();这段代码,这里将会调用initialValue方法从而返回初始值。

四、ThreadLocal 内存泄漏问题

ThreadLocalMap中的Entry中,ThreadLocal作为key,是作为弱引用进行存储的。当ThreadLocal不再被作为强引用持有时,会被GC回收,这时ThreadLocalMap对应的ThreadLocal就变成了null。而根据文档所叙述的,当key == null时,这时就可以默认该键不再被引用,该Entry就可以被直接清除,该清除行为会在Entry本身的set()/get()/remove()中被调用。

一般情况下,线程在执行结束时,自然也会消除其对value的引用,使得Value能够被GC回收。但是在使用线程池或者其他特殊情况下的时候,会存在线程复用的情况,这时候Value的值依然能获取到,可能就存在内存泄漏的隐患了。所以我们推荐通过手动将value的值设置为null(即调用ThreadLocal.remove()方法)以规避内存泄漏的风险。

五、推荐资料

  1. 一针见血 ThreadLocal

  2. 《Java并发编程的艺术》

[Android进阶】Handler机制原理解析_android handler的机制和原理 按照国际惯例,给大家分享一套十分好用的Android进阶资料:《全网最全Android开发笔记》。整个笔记一共8大模块、729个知识点,3382页,66万字,可以说覆盖了当下Android开发最前沿的技术点,和阿里、腾讯、字节等等大厂面试看重的技术。因为所包含的内容足够多,所以,这份笔记不仅仅可以用来当学习资料,还可以当工具书用。如果你需要了解某个知识点,不管是Shift+F 搜索,还是按目录进行检索,都能用最快的速度找到你要的内容。 阅读详情

相关推荐

Handler消息机制详解

转载请注明链接:http://blog.youkuaiyun.com/feather_wch/article/details/79263855 介绍Handler、Looper、MessageQueue、ThreadLocal和主线程ActivityThread等内容 Android的消息机制 版本:2018/2/6-1 Android的消息机制 消息机制概述 ThreadLocal 消息...

feather(猎羽) 2322

Android Handler机制——ThreadLocal

Android Handler机制——ThreadLocal 一、构造及初始化 public ThreadLocal() { }   ThreadLocal本身并不存储主要信息,这从它的构造函数就可看出大概,其并没有强耦合其他类,它主要的作用是提供相关静态方法。但ThreadLocal有个内部类ThreadLocalMap,其中有个数组用于存储相关对象(本质是一个hashmap),而ThreadLocalMap则被存储与Thread对象中。 类关系图如下: 二、get/set public T get(

qq_38401088的博客 512

Android Handler消息机制详解

Android应用程序是通过消息驱动实现的,因此,Handler机制对于Android应用程序的运行极其重要。 本文详细的介绍了Handler、Looper、MessageQueue、Message、ThreadLocal,内容较长,可以分部分进行学习。文章未详尽之处,欢迎交流,描述有误之处,欢迎指正。 点关注,不迷路;点收藏,你更强;点点赞,我心欢。

u011532067的博客 1192

Handler-ThreadLocal分析

提供了线程本地变量保存的功能。线程本地变量的修改由的set()实现,读取由的get()方法实现。实例通常会被定义成static字段,这些字段与一个线程的状态关联 ( 例如,用户ID 或 业务ID )。依据 app 启动过程,主线程下的使用进行对应的分析。

Zen@sz 博客 484

android Handler机制之ThreadLocal详解

概述我们在谈Handler机制的时候,其实也就是谈Handler、Message、Looper、MessageQueue之间的关系,对于其工作原理我们不做详解(Handler机制详解)。 Message:Handler发送、接收和处理的消息对象 Looper:每个线程只能拥有一个Looper.它的looper()方法负责循环读取MessageQueue中的消息并将读取到的消息交给发送该消息的hand

xiangzhihong8的专栏 8879

PADS Layout新手必看:从元件摆放到地线处理的10个实用技巧

本文为PADS Layout新手提供了10个实用技巧,涵盖元件摆放、地线处理等关键环节。从功能模块化布局到高频信号处理,再到电磁兼容性设计,帮助初学者快速掌握PCB设计核心技能,提升Layout效率和质量。特别适合需要优化PADS Layout工作流程的设计师参考。

stone的博客 252

Android的消息机制之ThreadLocal的工作原理

提到消息机制大家应该都不陌生,在日常开发中不可避免地要涉及到这方面的内容。从开发的角度来说,Handler是Android消息机制的上层接口,这使得开发过程中只需要和Handler交互即可。Handler的使用过程很简单,通过它可以轻松地将一个任务切换到Handler所在的线程中去执行。很多人认为Handler的作用是更新UI,这说的的确没错,但是更新UI仅仅是Handler的一个特殊的使用场景,

singwhatiwanna 4万+

联邦学习模型投毒研究进展

在联邦学习中,多个设备(如移动设备、IoT设备等)本地训练模型,然后将更新的模型参数上传到服务器进行聚合。

2401_82375734的博客 1265

Handler和ThreadLocal的原理解析

通过创建新线程的方式。msg.target是个啥呢,我们追到Message里面不难发现其实它就是我们发送消息的Handler,这写法是不是很聪明,当从MessageQueen中捞出Message后,我们就能直接调用Handler的dispatchMessage,然后就会走到我们的Handler的handleMessage了。Handler使用是用来进行线程间通信的,所以新开启的线程是会持有Handler引用的,如果在Activity等中创建Handler,并且是非静态内部类的形式,就有可能造成内存泄漏。

qq_27391737的博客 702

C#国产化技术路线(全栈落地指南,适配信创场景)

本文详细介绍了C#语言在信创产业中的国产化适配方案。核心方案基于.NET8框架,通过硬件架构适配、基础软件替换和打包部署优化三个层面进行改造,无需更换开发语言即可适配国产CPU和操作系统。文章系统讲解了开发工具选择、全栈适配层改造、数据库替换等技术要点,并提供了桌面应用和服务端应用的具体开发流程。针对政务、金融、能源等典型场景给出了可直接套用的技术组合,同时总结了10个关键避坑点。该方案可复用C#开发特性,实现低成本迁移,已在多个行业成功落地。

weilinc的专栏 1196

ColorOS13系统账户锁与密码锁破解全指南:从恢复模式到激活绕过

本文针对ColorOS13系统用户,详细解析了忘记锁屏密码(数字/图案锁)和遭遇OPPO账户锁(激活锁)的合法解决方案。核心是通过官方恢复模式进行格式化操作清除锁屏密码,并强调账户锁需通过密码找回或官方售后等正规途径解除。文章旨在帮助设备合法所有者恢复使用权,并提供了安全操作指南与数据备份建议。

weixin_28304023的博客 962

Android消息机制之ThreadLocal的工作原理

转载自:https://blog.youkuaiyun.com/singwhatiwanna/article/details/48350919 从开发的角度来说,Handler是Android消息机制的上层接口,这使得开发过程中只需要和Handler交互即可。Handler的使用过程很简单,通过它可以轻松的将一个任务切换到Handler所在的线程中去执行。很多人认为Handler的作用是更新UI,这说的的确...

u011337574的专栏 415

用Python玩转Iris数据集:从数据加载到可视化分析的完整指南

本文提供了使用Python处理Iris数据集的完整指南,涵盖数据加载、探索性分析、特征工程和可视化呈现等关键步骤。通过Pandas、NumPy、Matplotlib和Seaborn等工具,读者将学习如何从零开始完成一个机器学习项目的数据分析流程,掌握数据科学的核心技能。

j2k3l4的博客 849

【Android】Handler消息机制

Android消息机制学习分享

m0_74448051的博客 1649

PCIe Gen4眼图测试实战:如何用示波器快速定位信号完整性问题(附避坑指南)

本文详细解析了PCIe Gen4眼图测试中的信号完整性诊断方法,通过示波器操作技巧和实战案例,帮助工程师快速定位抖动、反射等信号问题。特别针对眼图闭合、阻抗失配等常见问题提供了避坑指南和解决方案,提升高速信号调试效率。

weixin_29230773的博客 372

告别C盘空间焦虑!Miniforge环境路径精准配置全攻略

本文深入解析Miniforge虚拟环境默认占用C盘空间的根本原因,即未正确配置`.condarc`文件中的`envs_dirs`路径优先级。通过详细的诊断步骤与配置命令,指导用户将环境路径精准迁移至指定磁盘(如D盘),并分享禁用自动激活、使用`--prefix`参数等高阶技巧,帮助开发者彻底告别C盘空间焦虑,实现虚拟环境的整洁与可控管理。

weixin_28831399的博客 238

安卓的Handler机制

Android Handler机制解析 Handler机制是Android实现线程间通信的核心框架,主要由四个关键组件构成: Handler:消息发送和处理的桥梁,负责发送消息(sendMessage)和处理消息(handleMessage) Message:消息数据结构,包含what、obj、arg1/arg2等字段 MessageQueue:消息队列,负责消息的存储和管理 Looper:消息循环,从队列中取出消息并分发 每个线程只能拥有一个Looper,通过ThreadLocal保证线程隔离。使用Han

weixin_44078411的博客 1169

杰理SDK入门教程(六):自定义按键事件

这篇教程介绍了在杰理AC695N芯片上实现自定义按键功能的完整流程,包含三个核心步骤:首先在key_event_deal.h文件中添加按键枚举定义;然后在adkey_table.c配置按键映射表,按模式和行为类型设置按键值;最后在app_common.c的消息处理函数中添加自定义按键逻辑。教程强调需注意不同模式按键表的列定义差异,并提供了具体代码示例,最后指导完成编译测试验证。全文结构清晰,配有关键代码截图,适合开发者快速上手自定义按键功能开发。

qq_42014563的博客 1016

Android全面解析之由浅及深Handler消息机制

前言 很高兴遇见你~ 欢迎阅读我的文章。 关于Handler的博客可谓是俯拾皆是,而这也是一个老生常谈的话题,可见的他非常基础,也非常重要。但很多的博客,却很少有从入门开始介绍,这在我一开始学习的时候就直接给我讲Looper讲阻塞,非常难以理解。同时,也很少有系统地讲解关于Handler的一切,知识比较零散。我希望写一篇从入门到深入,系统地全面地讲解Handler的文章,帮助大家认识Handler。 这篇文章的讲解深度循序渐进,不同程序的读者可选择对应的部分查看: 第一部分是对于Handler的入门概述。

一只修仙的猿 1万+

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Android的消息机制 Handler、MessageQueue、ThreadLocal、Looper

handler的作用:   具体来说,有时候需要执行一个比较耗时的工作,在主线程执行是非常不友好的,于是我们从子线程中去执行,可能是读取文件也可能是网络请求。当子线程中的工作完成以后可能需要在页面上显示信息,但在Android的规则中,不能在子线程中更新ui,这个时候就可以通过handler切换到主线程中进行ui操作。简单的说,将一个任务切换到某个指定的线程中去执行。   Android的消息机制主要是指Handler的运行机制,Handler的运行需要MessageQueue和looper的支撑。Mess

来来来,走一走 2860

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Android消息机制-Handler

基本概述在Android开发中提到消息机制应该所有人都不陌生,但是估计也很少有人能把消息机制详细地说出个所以然来,我们在开发过程中,有很多技术痛点,就是明明很多时候我们在用的东西,我们却不知道是为什么,它具体是个什么东西,很多时候我们只在乎它如何被拿来用,而不去关心更深层次的东西,也许这就是初中级向上进阶的阻碍吧。还好,我意识到了这一点,尽力去了解更多事实的真相…一不小心说了这么多废话,言归正传吧。

戚继光的博客 1689

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

死磕Android_Handler机制你需要知道的一切

文章目录1. 前言2. ThreadLocal工作原理2.1 ThreadLocal demo2.2 ThreadLocal源码理解3. MessageQueue 消息队列3.1 消息队列插入3.2 消息队列查询(next)4. Looper4.1 Looper初始化4.2 Looper#loop5. Handler6. 用一句话总结一下安卓的消息机制7. 消息机制在主线程中的应用7.1 关于主线...

潇风寒月 3415

Android的消息机制(Handler的工作原理)

Android的消息机制 Android中的消息机制其实也就是Handler的运行机制。Android中通过使用Handler来进行更新UI的操作。因为Android的UI更新是单线程模型,UI控件也都是非线程安全的。其原因是如果给UI控件加锁,那么效率将会变得底下的同时还会将UI访问的逻辑变得复杂。 Handler的运行基于MessageQueue和Looper的支撑。MessageQue...

u012401336的博客 3021

理解Android中ThreadLocal的工作原理

消息处理机制在Andorid中发挥着非常重要的作用,而消息处理机制的实现却离不开ThreadLocal,理解ThreadLocal的工作原理有助于我们更深入地理解Android的消息处理机制。当然,ThreadLocal在java中的多线程问题上也是很实用的。

reakingf的博客 2203

android Handler Looper,MessageQueue消息机制原理

安卓消息处理类: Looper、Handler、MessageQueue、Message、ThreadLocal、ThreadLocal.Values、HandlerThread。 Looper: 线程默认是没有消息循环的,要为一个线程创建一个消息循环通过调用prepare(),然后在调用loop()方法进入消息循环(这意味着线程将一直在此方法循环)。例如: class LooperThr

ZhouLi_优快云的专栏 9992

Android中Handler机制

1.Handler概述Handler 可以将一个任务切换到Handler所在线程中去执行,Handler的主要作用是更新UI,有时候需要在子线程进行耗时的I/O操作(读取文件或者访问网络),当耗时任务完成后,需要在UI线程中做一些改变,由于我们不能在子线程中访问UI控件,否则会发生异常,通过Handler就可以将跟新UI操作切换到主线程中执行。2.Handler机制注意:子线程中默认是没有Loope

蓝枫 1236
上一篇: Android Handler 机制(四):屏障消息(同步屏障sync barrier,异步消息 )IdelHandler
下一篇: Android Handler 机制(六):如何检测性能卡顿
阿杰、
博客等级 码龄11年 13粉丝 47原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值