【Android】Handler(四)Looper的相关知识点
Handler 机制是 Android 多线程间通信的一种常见方式。每个 Handler 对象由一个 Looper 和一个 MessageQueue 组成,用于将 Message 对象处理到指定的线程中。通过创建 Handler 实例,在子线程中创建 Message 对象并通过sendMessage()方法发送给 Handler,然后 Handler 会接收到消息并处理它。最后,Handler 在处理完消息后会将消息回传至主线程,再通过dispatchMessage()方法交由UI线程处理。
Looper 中在每一个线程上只有一个
ThreadLocal
线程是一个程序中执行的一条执行路径。每个线程都拥有自己的栈空间和寄存器等资源,因此它们之间是互相独立的。为了避免在多线程环境下出现资源竞争、数据不一致等问题,需要对线程之间的访问进行隔离和控制。其中一个解决方案就是使用 ThreadLocal。
ThreadLocal 是一个 Java 中的类,它可以在每个线程中存储和获取与其他线程隔离的变量值。具体来说,每个 ThreadLocal 对象都会存储到当前线程的 ThreadLocalMap 中。ThreadLocalMap 是一个以 ThreadLocal 对象为键、以变量值为值的 Map,它可以快速地访问和获取每个线程所拥有的 ThreadLocal 变量的值。当一个线程结束时,它所持有的 ThreadLocalMap 也会随之销毁。
在 Android 中,Looper 是一个消息循环机制,它可以让线程在消息队列中等待并处理消息。每个 Looper 对象都对应一个消息队列(MessageQueue)和一个函数(loop()),它可以不断地从消息队列中取出消息进行处理。
当我们调用 Looper.prepare() 方法时,该方法会为当前线程创建一个新的 Looper 对象。在 prepare() 方法内部,Looper 会将当前线程的 Looper 对象存储在一个名为 sThreadLocal 的 static 变量中。这个变量是一个 ThreadLocal 对象,这个变量是一个 ThreadLocal 对象,它可以在每个线程中存储和获取与其他线程隔离的变量值。由于 sThreadLocal 是一个 static 变量,所以它在整个应用程序中只存在一个实例,但是每个线程都可以通过这个变量来访问和管理自己的 Looper 对象。
具体来说,sThreadLocal 变量会存储到当前线程的 Thread 类中的 ThreadLocalMap 中。当我们需要使用某个线程的 Looper 对象时,只需要调用 Looper.myLooper() 方法即可获取当前线程所对应的 Looper 对象。这个方法会先获取当前线程的 ThreadLocalMap,然后从中获取到 sThreadLocal 变量对应的值,也就是当前线程的 Looper 对象。
通过使用 sThreadLocal 变量和 ThreadLocalMap,Looper 可以实现多线程之间的隔离和独立,确保每个线程都有自己的 Looper 对象。这个机制是 Android 框架中异步消息传递机制的核心之一,也是实现各种异步操作的基础。
Looper 的阻塞
Looper 中有两个方面的阻塞:
Message 不到时间,空转等待:
在某些情况下,Message 还没到执行时间之前,Looper 会一直进行循环,不断地空转等待,直到 Message 到了执行时间才继续执行。这种情况下,Looper 并没有真正的阻塞,它只是在等待 Message 到来。
MessageQueue 为空,阻塞等待:
如果 MessageQueue 中没有消息,那么 Looper 会进入阻塞状态,等待新的消息到来。这个过程中,Looper 对 CPU 的占用率非常低,因此不会对系统性能产生过大的影响。
需要注意的是,第二种情况可能会导致线程进入无限等待状态,从而造成应用程序的假死或 ANR(Application Not Responding)错误。
Looper设计模式
Looper 使用了生产者-消费者设计模式,其中 MessageQueue 充当生产者,Looper 的 loop() 方法充当消费者。
具体来说,MessageQueue 维护了一个消息队列,消息队列中的消息相当于生产者生产出来的产品,Looper 对消息队列进行消费和处理。在这个过程中,MessageQueue 和 Looper 之间是解耦的,它们可以独立地进行操作和管理。
当 MessageQueue 中产生新的消息时,它会将消息加入到消息队列的尾部,并通知 Looper 轮询消息队列。Looper 取到消息后,会依次对每个消息进行分发和执行,直到消息队列为空。整个过程中,MessageQueue 和 Looper 都不需要关心对方的具体实现细节,只需要按照约定好的协议进行数据传输和处理。
这种设计模式的优点是可以有效地降低耦合度,并提高代码的可读性和维护性。通过将生产者和消费者分离,我们可以更灵活地添加或修改消息的生产和消费方式,而无需对整个系统进行大规模的修改。同时,在多线程环境下,生产者和消费者之间的协作也可以有效避免竞争和冲突,保证了系统的线程安全性。
synchronized
Looper 中使用了 synchronized 关键字来实现线程之间的同步。具体来说,Looper 中的 loop() 方法和 MessageQueue 中的 enqueueMessage() 方法都是加了 synchronized 关键字的方法,它们在执行时都会获取 MessageQueue 对象的锁,确保同一时刻只能有一个线程访问和修改 MessageQueue。
这种同步机制是为了避免多个线程同时操作 MessageQueue 时产生的竞争和冲突。在 Android 系统中,生产者和消费者之间是通过 Message 消息进行通信的,因此必须保证 MessageQueue 中的消息能够正确地被分发和执行。如果没有同步机制,就会出现多个线程同时向 MessageQueue 中添加消息或者同时取出并处理消息的情况,从而导致数据不一致性和程序崩溃等问题。
例如:
Looper.prepare()
方法中创建和初始化 Looper 对象时,会加锁。由于每个线程只有一个 Looper 实例,因此需要确保在创建新的 Looper 实例的同时,不会出现多个线程同时执行该方法的情况。
Looper.loop()
方法中执行消息循环时,会加锁。该方法会不断地从 MessageQueue 中取出消息进行分发和执行,如果不加锁就会出现多个线程同时访问和修改 MessageQueue 的情况,从而导致数据一致性和程序错误。
MessageQueue.enqueueMessage()
方法中添加消息到 MessageQueue 时,会加锁。该方法会将新消息添加到 MessageQueue 的尾部,并通知正在等待消息的线程有新的消息可用。如果不加锁就会出现多个线程同时向 MessageQueue 添加消息的情况,可能导致消息顺序错乱或者丢失。
MessageQueue.next()
方法中获取下一个要处理的消息时,会加锁。该方法会从 MessageQueue 的头部取出下一个要处理的消息,并返回给调用者。如果不加锁就会出现多个线程同时取出并执行同一条消息的情况,可能导致数据的不一致性和程序的错误。
Looper 使用 synchronized 原因:
执行效率:
synchronized 是 Java 中最基本和常用的同步机制,由 JVM 内部实现,可以比较方便地保证线程安全。相对于其他的锁实现,synchronized 的执行效率相对较高,避免了过多的性能开销。
粒度控制:
在 Looper 的实现中,使用 synchronized 关键字可以比较方便地控制锁的粒度,避免了锁定过大的代码块或方法,从而提高了并发性能。如果使用其他类型的锁,可能会存在锁竞争或死锁,影响程序正确性和性能。
可重入性:
synchronized 是可重入锁,即一个线程在持有锁的情况下还可以重复获取锁,而不会出现死锁或其他的异常。在 Looper 中,需要实现消息循环并处理消息时可能需要多次进入锁定代码块或方法,因此使用可重入锁可以避免代码逻辑出错。
synchronized 是 Java 中最基本和常用的同步机制,而且在大多数情况下可以提供良好的并发性能和可靠性。对于轻量级的同步需求,synchronized 是不错的选择。
Handler线程间通信机制通过什么实现
Handler 是一种消息处理机制,它提供了一种在不同线程之间进行通信的方式。由于·Handler 是在同一个进程中创建的,因此它们可以共享进程中的内存,从而实现线程间的通信
。
当我们在一个线程中创建 Handler 时,这个 Handler 会与当前线程中的 Looper 绑定,并创建一个 MessageQueue 对象。然后,我们可以使用这个 Handler 向该线程中的 MessageQueue 发送消息(即构造 Message 对象并添加到该队列中),这些消息就会被 Looper 接收并交给对应的 Handler 进行处理。
当我们需要在其他线程中发送消息时,就需要使用 Handler 的 post 方法或者 sendMessage 方法,这些方法会将要发送的消息封装成一个 PendingMessage 对象,并加入到目标线程的消息队列中。最终,目标线程中的 Looper 会将这个 PendingMessage 对象转化成 Message 对象,并交给绑定的 Handler 进行处理。
相关文章:

【Android】Handler(四)Looper的相关知识点
Handler 机制是 Android 多线程间通信的一种常见方式。每个 Handler 对象由一个 Looper 和一个 MessageQueue 组成,用于将 Message 对象处理到指定的线程中。通过创建 Handler 实例,在子线程中创建 Message 对象并通过sendMessage()方法发送给 Handler&a…...

Redis缓存雪崩及解决办法
缓存雪崩 1.缓存雪崩是指在同- -时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到 达数据库,带来巨大压力。 2.解决方案: ◆给不同的Key的TTL添加随机值 ◆利用Redis集群提高服务的可用性 ◆给缓存业务添加降级限流策略 降级可做为系统的保底…...

Maven私服仓库配置-Nexus详解
目录 一、什么是Maven私服?二、Maven 私服优势三、Maven 私服搭建四、Sonatype Nexus介绍五、Nexus仓库属性和分类六、Nexus仓库配置以及创建仓库七、Nexus配置用户角色八、Maven SNAPSHOT(快照)九、项目当中配置Nexus上传依赖十、项目当中配置Nexus下载依赖十一、测…...

Systrace系列10 —— Binder 和锁竞争解读
本文主要是对 Systrace 中的 Binder 和锁信息进行简单介绍,简单介绍了 Binder 的情况,介绍了 Systrace 中 Binder 通信的表现形式,以及 Binder 信息查看,SystemServer 锁竞争分析等。 Binder 概述 Android 的大部分进程间通信都使用 Binder,这里对 Binder 不做过多的解释…...

React Hooks中使用useState异步回调获取不到最新值的问题
ReactHook中useState异步回调获取不到最新值及解决⽅案 预先了解 setState 的两种传参⽅式 1、直接传⼊新值 setState(options); 列如: const [state, setState] useState(0); setState(state 1); 2、传⼊回调函数 setState(callBack); 例如: …...

JavaScript 高级 (完结)
目录 深浅拷贝 浅拷贝 深拷贝 递归实现深拷贝 js库lodash里面cloneDeep内部实现了深拷贝 JSON序列化 异常处理 throw 抛异常 try /catch 捕获异常 debugg 处理this this指向 普通函数 箭头函数 改变this call() apply() bind() call apply bind 总结 性能优化…...

【P30】JMeter 事务控制器(Transaction Controller)
文章目录 一、事务控制器(Transaction Controller)参数说明二、测试计划设计2.2.1、勾选 Generate parent sample2.2.1、勾选 Include duration of timer and pre-post processors in generated sample 一、事务控制器(Transaction Controlle…...

【MySQL】MySQL的事务原理和实现?
文章目录 MySQL事务的底层实现原理一、事务的目的可靠性和并发处理 二、实现事务功能的三个技术2.1 redo log 与 undo log介绍2.1.1 redo log2.1.2undo log 2.2 mysql锁技术2.2.1 mysql锁技术 2.3 MVCC基础 三、事务的实现3.1 原子性的实现3.1.1 undo log 的生成3.1.2 根据undo…...

S7-300Smart1200的ISO on TCP通信
1、西门子PLC的通信资源 1.1 S7-1200 的PROFINET 通信口 S7-1200 CPU 本体上集成了一个 PROFINET 通信口,支持以太网和基于 TCP/IP 的通信标准。使用这个通信口可以实现 S7-1200 CPU 与编程设备的通信,与HMI触摸屏的通信,以及与其它 CPU 之间的通信。这个PROFINET 物理接口…...

Spark写入Hive报错Mkdir failed on :com.alibaba.jfs.JindoRequestPath
1. 报错内容 23/05/31 14:32:13 INFO [Driver] FsStats: cmdmkdirs, srcoss://sync-to-bi.[马赛克].aliyuncs.com/tmp/hive, dstnull, size0, parameterFsPermission:rwx-wx-wx, time-in-ms32, version3.5.0 23/05/31 14:32:13 ERROR [Driver] ApplicationMaster: User class …...

分布式id解决方法--雪花算法
uuid,jdk自带,但是数据库性能差,32位呀。 mysql数据库主键越短越好,Btree产生节点分裂,大大降低数据库性能,所以uuid不建议。 redis的自增,但是要配置维护redis集群,就为了一个id&a…...

5年经验之谈:月薪3000到30000,测试工程师的变“行”记
自我介绍下,我是一名转IT测试人,我的专业是化学,去化工厂实习才发现这专业的坑人之处,化学试剂害人不浅,有毒,易燃易爆,实验室经常用丙酮,甲醇,四氯化碳,接触…...

PMP考试都是什么题?
PMP新版大纲加入了ACP敏捷管理的内容,说是敏捷混合题型占到了 50%,但是这次318的考试,敏捷题占了大半,都说敏捷和情景快要占到80%-90%。 所以有友友说开了四个小时盲盒,题目读不懂,或者觉得4个选项都不对或…...

macbook2023系统清理软件cleanmymac中文版
cleanmymac x 中文版基本都是大家首选Mac清理软件了。它集各种功能于一身,几乎满足用户所有的清理需求。它可以清理,优化,保养和监测您的电脑,确保您的Mac运行畅通无阻!支持一键快速清理Mac,快速检查并安全…...

基于Python+AIML+Tornado的智能聊天机器人(NLP+深度学习)含全部工程源码+语料库 适合个人二次开发
目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境Tornado 环境 模块实现1. 前端2. 后端3. 语料库4. 系统测试 其它资料下载 前言 本项目旨在利用AIML技术构建一个聊天机器人,实现用户通过聊天界面与机器人交互的功能。通过提供的工程源代码…...

算法Day15 | 层序遍历,102,107,199,637,429,515,116,117,104,111,226,101
Day15 层序遍历102.二叉树的层序遍历107.二叉树的层次遍历 II199.二叉树的右视图637.二叉树的层平均值429.N叉树的层序遍历515.在每个树行中找最大值116.填充每个节点的下一个右侧节点指针117.填充每个节点的下一个右侧节点指针II104.二叉树的最大深度111.二叉树的最小深度 226…...

Prometheus+Grafana学习(十一)安装使用pushgateway
Pushgateway允许短暂和批量作业将其指标暴露给 Prometheus。由于这些工作的生命周期可能不足够长,不能够存在足够的时间以让 Prometheus 抓取它们的指标。Pushgateway 允许它们可以将其指标推送到 Pushgateway,然后 Pushgateway 再将这些指标暴露给 Prom…...

深入理解C/C++预处理器指令#pragma once以及与ifndef的比较
#pragma once用法总结 为了防止重复引用造成二义性 在C/C中,在使用预编译指令#include的时候,为了防止重复引用造成二义性,通常有两种方式 第一种是#ifndef指令防止代码块重复引用,比如说 #ifndef _CODE_BLOCK #define _CODE_BLO…...

git 环境配置 + gitee拉取代码
好嘛 配环境的时候 老是忘记这个命令行 干脆自己写一个记录一下 也不用搜了 1.先从git官网下载git 安装 2.然后从gitee拉取代码的时候提示 这是因为换了新电脑没有加入新的公钥啦 哎 所以老是记不住命令行 first : git config --global user.name “Your Name” …...

港联证券|港股拥抱特专科技企业 内资券商“修炼内功”蓄势而为
港股市场新一轮改革举措渐次落地。特别是港交所推出特专科技公司上市机制,吸引符合资格的科技企业申请赴港上市,成为这一轮港股市场改革的“重头戏”。 作为香港资本市场的重要参与者,内资券商立足香港、背靠内地、辐射全球,走出一…...

多项创新技术加持,实现零COGS的Microsoft Editor语法检查器
编者按:Microsoft Editor 是一款人工智能写作辅助工具,其中的语法检查器(grammar checker)功能不仅可以帮助不同水平、领域的用户在写作过程中检查语法错误,还可以对错误进行解释并给出正确的修改建议。神经语法检查器…...

Python编程环境搭建:Windows中如何安装Python
在 Windows 上安装 Python 和安装普通软件一样简单,下载安装包以后猛击“下一步”即可。 Python 安装包下载地址:https://www.python.org/downloads/ 打开该链接,可以看到有两个版本的 Python,分别是 Python 3.x 和 Python 2.x&…...

Sui Builder House首尔站倒计时!
Sui主网上线后的第一场Builder House活动即将在韩国首尔举行,同期将举办首场线下面对面的黑客松。活动历时两天,将为与会者提供独特的学习、交流和娱乐的机会。活动详情请查看:Sui Builder House首尔站|主网上线后首次亮相。 Sui…...

Java设计模式-状态模式
简介 在软件开发领域,设计模式是一组经过验证的、被广泛接受的解决问题的方案。其中之一是状态模式,它提供了一种优雅的方式来管理对象的不同状态。 状态模式是一种行为型设计模式,它允许对象在内部状态发生改变时改变其行为。状态模式将对…...

智慧社区用什么技术开发
智慧社区是指利用信息技术和先进的管理理念,将社区内的各种公共服务进行整合和优化,提高社区居民的生活品质和社区管理的效率。为了实现智慧社区的建设,需要采用多种技术,包括但不限于以下几种: 1.物联网技术…...

多线程 线程池饱和策略
RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。 这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。 在JDK 1…...

进程间通信之信号
进程间通信之信号 1. 信号2. 信号由谁产生?3. 有哪些信号4. 信号的安装5. 信号的发送1) 使用kill函数2)使用alarm函数3) 使用raise6.发送多个信号7. 信号集1. 信号 什么是信号? 信号是给程序提供一种可以处理异步事件的方法,它利用软件中断来实现。不能自定义信号,所有信号…...

二分查找三道题
二分查找 两种写法:左闭右闭[left,right]、左闭右开[left,right) 主要有几点不同:1. right是从num.length开始还是从num.length-1开始。2.left<还是<right。3.rightmid还是mid1 左闭右闭写法: public int search(int[] nums, int targ…...

MyBatis 框架
MyBatis 框架 MyBatis 简介搭建 MyBatis 开发环境核心配置文件详解mapper 映射文件(实现增删改查)MyBatis获取参数值的两种方式MyBatis的各种查询功能特殊SQL的执行自定义映射resultMapresultMap 字段和属性的映射多对一映射处理一对多映射处理 动态SQLM…...

【C++】虚表和虚基表到底有哪些区别?
虚表和虚基表 虚表虚基表虚拟继承和虚函数都存在时的对象模型 虚表 我们知道,如果类中声明了的方法是用virtual进行修饰的,则说明当前这个方法要作为虚函数,而虚函数的存储和普通函数的存储是有区别的 当有虚函数声明时,编译器会…...