当前位置: 首页 > news >正文

Android Handler 通过线程安全的 MessageQueue 和底层唤醒机制实现跨线程通信

目录

一、MessageQueue 的线程安全实现

1. 消息队列的同步锁(synchronized)

2. 消息顺序与延时处理

二、底层唤醒机制:从 Java 到 Linux 内核

1. 消息插入后的唤醒逻辑

2. Native 层实现(基于 Linux 的 eventfd 和 epoll)

三、完整流程:跨线程通信的步骤分解

四、设计优势与性能考量

五、总结

相关推荐


        Android 中的 Handler 跨线程通信机制 依赖于两个核心设计:线程安全的 MessageQueue 和 高效的底层唤醒机制。以下是详细的分步解析:

一、MessageQueue 的线程安全实现

1. 消息队列的同步锁(synchronized)
  • 关键方法 enqueueMessage()
    当通过 Handler 发送消息(如 sendMessage() 或 post())时,最终会调用 MessageQueue.enqueueMessage() 方法将消息插入队列。
    // 源码简化示例(Android SDK)
    boolean enqueueMessage(Message msg, long when) {synchronized (this) {  // 同步锁,确保原子性操作// 将消息按时间顺序插入队列// ...if (needWake) {nativeWake(mPtr); // 唤醒目标线程的 Looper}}return true;
    }// 源码简化示例(Android SDK)boolean enqueueMessage(Message msg, long when) {// 消息合法性检查:每个消息必须绑定一个 Handler(即 msg.target),否则无法确定消息由谁处理。if (msg.target == null) {throw new IllegalArgumentException("Message must have a target.");}synchronized (this) {// 同步锁,确保原子性操作if (msg.isInUse()) {// 防止消息被重复插入队列(如已被回收或正在处理)throw new IllegalStateException(msg + " This message is already in use.");}if (mQuitting) {IllegalStateException e = new IllegalStateException(msg.target + " sending message to a Handler on a dead thread");Log.w(TAG, e.getMessage(), e);msg.recycle();// 回收消息并记录错误return false;}msg.markInUse();msg.when = when;Message p = mMessages;boolean needWake;if (p == null || when == 0 || when < p.when) {// 队列为空(p == null)// 消息需立即执行(when == 0)// 消息执行时间早于当前队首消息(when < p.when)msg.next = p;mMessages = msg;needWake = mBlocked;//唤醒队列if (p == null) {mLast = mMessages;}} else {// 若启用尾部跟踪(mLast 指向队列尾部),直接操作尾部指针提升插入效率if (Flags.messageQueueTailTracking()) {if (when >= mLast.when) {needWake = needWake && mAsyncMessageCount == 0;msg.next = null;mLast.next = msg;mLast = msg;} else {// Inserted within the middle of the queue.Message prev;for (;;) {prev = p;p = p.next;if (p == null || when < p.when) {break;}if (needWake && p.isAsynchronous()) {needWake = false;}}if (p == null) {/* Inserting at tail of queue */mLast = msg;}msg.next = p; // invariant: p == prev.nextprev.next = msg;}} else {Message prev;// 通过遍历链表找到插入位置for (;;) {prev = p;p = p.next;if (p == null || when < p.when) {break;// 找到插入位置}// 若存在异步消息,可能抑制唤醒if (needWake && p.isAsynchronous()) {needWake = false;}}msg.next = p; // invariant: p == prev.nextprev.next = msg;mLast = null;}}if (msg.isAsynchronous()) {// 异步消息(如 ViewRootImpl 的绘制任务)可绕过同步屏障(Sync Barrier),优先执行。mAsyncMessageCount++;//异步消息计数}// needWake == true,表示目标线程的 Looper 处于阻塞状态(mBlocked == true),需要唤醒以处理新消息。if (needWake) {nativeWake(mPtr);// 调用 Native 层唤醒}}return true;}
    • 同步锁的作用
      synchronized (this) 确保同一时间只有一个线程可以操作 MessageQueue,防止多线程并发插入消息时出现数据竞争(如队列链表断裂、消息丢失等问题)。
设计目标实现手段
线程安全synchronized 锁保护队列操作
消息顺序性按 when 时间排序的链表结构
高效唤醒eventfd + epoll 实现精准唤醒,避免忙等待
异步消息优先级通过同步屏障和异步消息计数优先处理高优先级任务
内存安全消息回收(msg.recycle())、退出状态检查(mQuitting
2. 消息顺序与延时处理
  • 消息按时间戳排序
    每个消息携带一个时间戳(when),MessageQueue 按时间顺序维护消息链表,确保延时消息(如 postDelayed())按预期执行。
  • 同步屏障(Sync Barrier)
    通过 postSyncBarrier() 插入同步屏障消息,可临时阻塞普通消息,优先处理异步消息(如 UI 渲染相关的高优先级任务)。

二、底层唤醒机制:从 Java 到 Linux 内核

1. 消息插入后的唤醒逻辑
  • 何时需要唤醒目标线程
    • 当消息插入到队列头部(即下一个待处理消息)时。
    • 当目标线程的 Looper 处于休眠状态(队列此前为空)。
  • 调用 nativeWake()
    enqueueMessage() 中通过 nativeWake(mPtr) 触发底层唤醒操作,mPtr 是 Native 层 MessageQueue 的指针。
2. Native 层实现(基于 Linux 的 eventfd 和 epoll)
  • nativeWake() 的 JNI 映射
    Java 层的 nativeWake() 对应 Native 层的 android_os_MessageQueue_nativeWake(),最终调用 Looper::wake()

    // Native 层代码(简化)
    void Looper::wake() {uint64_t inc = 1;write(mWakeEventFd, &inc, sizeof(uint64_t)); // 向 eventfd 写入数据
    }
    
  • eventfd:轻量级线程间通知机制

    • mWakeEventFd 是一个 eventfd 文件描述符,由 Looper 在初始化时创建。
    • 写入数据到 eventfd 会触发监听该文件描述符的线程唤醒。
  • epoll:I/O 多路复用监听事件

    // Looper 的主循环(pollOnce)
    int result = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
    if (result > 0) {if (eventItems[0].data.fd == mWakeEventFd) {read(mWakeEventFd, &counter, sizeof(uint64_t)); // 消费 eventfd 数据}// 处理其他事件(如 Input 事件、Binder 调用等)
    }
    
    • Looper 在消息循环中通过 epoll_wait() 监听 mWakeEventFd
    • 当其他线程调用 nativeWake() 写入数据时,epoll_wait() 返回,目标线程被唤醒,继续从 MessageQueue 中取出消息处理。

三、完整流程:跨线程通信的步骤分解

  1. 发送消息
    线程 A 调用 handler.sendMessage(msg),通过 enqueueMessage() 将消息插入线程 B 的 MessageQueue

    • 通过 synchronized 锁保证线程安全。
    • 若需要唤醒线程 B,触发 nativeWake()
  2. 底层唤醒
    nativeWake() 向线程 B 的 mWakeEventFd 写入数据,触发 epoll_wait() 返回,线程 B 退出休眠状态。

  3. 消息处理
    线程 B 的 Looper 调用 MessageQueue.next() 取出消息,分发给对应的 Handler.handleMessage() 处理。

四、设计优势与性能考量

  1. 线程隔离性

    • MessageQueue 严格绑定到线程,通过锁和底层唤醒机制隔离多线程操作。
    • 开发者无需手动处理线程同步问题。
  2. 高效性

    • 使用 epoll 和 eventfd 避免了忙等待(busy waiting),减少 CPU 空转。
    • 消息按时间排序,支持延时消息和优先级控制。
  3. 低延迟与高吞吐

    • 通过 epoll 多路复用监听多个事件源(如 UI 事件、Binder 调用),确保及时响应。

五、总结

  • 线程安全
    MessageQueue 通过 synchronized 锁保证多线程插入消息的安全性。

  • 高效唤醒
    结合 eventfd 和 epoll,在消息到达时精准唤醒目标线程,避免资源浪费。

  • 无缝跨线程通信
    Handler 机制隐藏了底层复杂性,开发者只需通过 post() 或 sendMessage() 即可实现线程间通信。

  • +-------------------------------------------+
    |           Android Handler 机制            |
    |        基于 MessageQueue 和 Native 唤醒       |
    +-------------------------------------------+
    | [主线程] [UI操作] <--> |Handler|           |
    |                         | sendMessage()   |
    |                         ↓                 |
    |                  +--------------+         |
    |                  | MessageQueue |         |
    |                  | (同步锁保护)   |         |
    |                  +--------------+         |
    |                         | nativeWake()    |
    |                         ↓                 |
    |               [eventfd] → [epoll_wait]    |
    |                         ↑                 |
    |                  +--------------+         |
    |                  | 工作线程 Looper|        |
    |                  | (处理耗时任务) |        |
    +-------------------------------------------+

相关推荐

Android Handle 机制常见问题深度解析-CSDN博客文章浏览阅读63次。本文聚焦Android开发中Handler机制的核心原理,系统解析线程与Handler/Looper/MessageQueue的关联、内存泄漏根源与解决方案、主线程与子线程的Handler使用差异、跨线程通信安全实现等关键知识点。通过代码示例与场景分析,阐明Handler的线程安全性、MessageQueue阻塞机制及HandlerThread适用场景,强调WeakReference防泄漏、Message复用优化等实践技巧。文章结构清晰,覆盖从基础概念到高级应用的完整知识链,助力开发者高效掌握 https://shuaici.blog.csdn.net/article/details/146340777Android 彻底掌握 Handler 看这里就够了-CSDN博客文章浏览阅读1.7k次,点赞16次,收藏19次。Handler 有两个主要用途:1、安排消息和可运行对象在将来的某个时间执行;2、将要在与您自己的线程不同的线程上执行的操作排入队列。_extends handler https://shuaici.blog.csdn.net/article/details/120238927


http://www.mrgr.cn/news/94927.html

相关文章:

  • 【机器学习-回归算法】
  • uniapp常用组件
  • Oracle常见系统函数
  • JavaScript基础-获取元素
  • Tomcat、Open Liberty 和 WebSphere Application Server (WAS) 的配置、调试和跟踪
  • 工作记录 2017-02-04
  • Java内部类
  • Business processes A bridge to SAP and a guide to SAP TS410 certification
  • 贪心算法作业参考:P1106,P4995,P5019
  • 基于大模型的喉癌全程预测与治疗方案优化研究报告
  • AcWing 3533:查找第K小数 ← sort+unique
  • Docker和containerd之概览(Overview of Docker and Containerd)
  • 蓝桥杯备赛(基础语法4)
  • ngx_http_core_srv_conf_t
  • JUC大揭秘:从ConcurrentHashMap到线程池,玩转Java并发编程!
  • Java高级编程深度解析:JVM底层原理、设计模式与Java 8+新特性实战
  • 剑指 Offer II 109. 开密码锁
  • Windows 图形显示驱动开发-WDDM 3.0功能- 硬件翻转队列(三)
  • 基于PyQt5与Open3D的轻量化BIM工具开发指南(上)‌
  • ★ Linux ★ 进程(上)