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

打印 上一主题 下一主题

主题 964|帖子 964|积分 2892

目次
一、MessageQueue 的线程安全实现
1. 消息队列的同步锁(synchronized)
2. 消息顺序与延时处理
二、底层唤醒机制:从 Java 到 Linux 内核
1. 消息插入后的唤醒逻辑
2. Native 层实现(基于 Linux 的 eventfd 和 epoll)
三、完整流程:跨线程通讯的步调分解
四、计划上风与性能考量
五、总结
相干推荐

        Android 中的 Handler 跨线程通讯机制 依靠于两个焦点计划:线程安全的 MessageQueue 和 高效的底层唤醒机制。以下是详细的分步解析:
一、MessageQueue 的线程安全实现

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



  • 关键方法 enqueueMessage()
    当通过 Handler 发送消息(如 sendMessage() 或 post())时,终极会调用 MessageQueue.enqueueMessage() 方法将消息插入队列。
    1. // 源码简化示例(Android SDK)
    2. boolean enqueueMessage(Message msg, long when) {
    3.     synchronized (this) {  // 同步锁,确保原子性操作
    4.         // 将消息按时间顺序插入队列
    5.         // ...
    6.         if (needWake) {
    7.             nativeWake(mPtr); // 唤醒目标线程的 Looper
    8.         }
    9.     }
    10.     return true;
    11. }
    12.     // 源码简化示例(Android SDK)
    13.     boolean enqueueMessage(Message msg, long when) {
    14.         // 消息合法性检查:每个消息必须绑定一个 Handler(即 msg.target),否则无法确定消息由谁处理。
    15.         if (msg.target == null) {
    16.             throw new IllegalArgumentException("Message must have a target.");
    17.         }
    18.         synchronized (this) {// 同步锁,确保原子性操作
    19.             if (msg.isInUse()) {
    20.                 // 防止消息被重复插入队列(如已被回收或正在处理)
    21.                 throw new IllegalStateException(msg + " This message is already in use.");
    22.             }
    23.             if (mQuitting) {
    24.                 IllegalStateException e = new IllegalStateException(
    25.                         msg.target + " sending message to a Handler on a dead thread");
    26.                 Log.w(TAG, e.getMessage(), e);
    27.                 msg.recycle();// 回收消息并记录错误
    28.                 return false;
    29.             }
    30.             msg.markInUse();
    31.             msg.when = when;
    32.             Message p = mMessages;
    33.             boolean needWake;
    34.             if (p == null || when == 0 || when < p.when) {
    35.                 // 队列为空(p == null)
    36.                 // 消息需立即执行(when == 0)
    37.                 // 消息执行时间早于当前队首消息(when < p.when)
    38.                 msg.next = p;
    39.                 mMessages = msg;
    40.                 needWake = mBlocked;//唤醒队列
    41.                 if (p == null) {
    42.                     mLast = mMessages;
    43.                 }
    44.             } else {
    45.                 // 若启用尾部跟踪(mLast 指向队列尾部),直接操作尾部指针提升插入效率
    46.                 if (Flags.messageQueueTailTracking()) {
    47.                     if (when >= mLast.when) {
    48.                         needWake = needWake && mAsyncMessageCount == 0;
    49.                         msg.next = null;
    50.                         mLast.next = msg;
    51.                         mLast = msg;
    52.                     } else {
    53.                         // Inserted within the middle of the queue.
    54.                         Message prev;
    55.                         for (;;) {
    56.                             prev = p;
    57.                             p = p.next;
    58.                             if (p == null || when < p.when) {
    59.                                 break;
    60.                             }
    61.                             if (needWake && p.isAsynchronous()) {
    62.                                 needWake = false;
    63.                             }
    64.                         }
    65.                         if (p == null) {
    66.                             /* Inserting at tail of queue */
    67.                             mLast = msg;
    68.                         }
    69.                         msg.next = p; // invariant: p == prev.next
    70.                         prev.next = msg;
    71.                     }
    72.                 } else {
    73.                     Message prev;
    74.                     // 通过遍历链表找到插入位置
    75.                     for (;;) {
    76.                         prev = p;
    77.                         p = p.next;
    78.                         if (p == null || when < p.when) {
    79.                             break;// 找到插入位置
    80.                         }
    81.                         // 若存在异步消息,可能抑制唤醒
    82.                         if (needWake && p.isAsynchronous()) {
    83.                             needWake = false;
    84.                         }
    85.                     }
    86.                     msg.next = p; // invariant: p == prev.next
    87.                     prev.next = msg;
    88.                     mLast = null;
    89.                 }
    90.             }
    91.             if (msg.isAsynchronous()) {
    92.                 // 异步消息(如 ViewRootImpl 的绘制任务)可绕过同步屏障(Sync Barrier),优先执行。
    93.                 mAsyncMessageCount++;//异步消息计数
    94.             }
    95.             // needWake == true,表示目标线程的 Looper 处于阻塞状态(mBlocked == true),需要唤醒以处理新消息。
    96.             if (needWake) {
    97.                 nativeWake(mPtr);// 调用 Native 层唤醒
    98.             }
    99.         }
    100.         return true;
    101.     }
    复制代码

    • 同步锁的作用
      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()。
    1. // Native 层代码(简化)
    2. void Looper::wake() {
    3.     uint64_t inc = 1;
    4.     write(mWakeEventFd, &inc, sizeof(uint64_t)); // 向 eventfd 写入数据
    5. }
    复制代码
  • eventfd:轻量级线程间关照机制

    • mWakeEventFd 是一个 eventfd 文件形貌符,由 Looper 在初始化时创建。
    • 写入数据到 eventfd 会触发监听该文件形貌符的线程唤醒。

  • epoll:I/O 多路复用监听事件
    1. // Looper 的主循环(pollOnce)
    2. int result = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
    3. if (result > 0) {
    4.     if (eventItems[0].data.fd == mWakeEventFd) {
    5.         read(mWakeEventFd, &counter, sizeof(uint64_t)); // 消费 eventfd 数据
    6.     }
    7.     // 处理其他事件(如 Input 事件、Binder 调用等)
    8. }
    复制代码

    • Looper 在消息循环中通过 epoll_wait() 监听 mWakeEventFd。
    • 当其他线程调用 nativeWake() 写入数据时,epoll_wait() 返回,目的线程被唤醒,继续从 MessageQueue 中取出消息处理。

三、完整流程:跨线程通讯的步调分解


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

    • 通过 synchronized 锁保证线程安全。
    • 若必要唤醒线程 B,触发 nativeWake()。

  • 底层唤醒
    nativeWake() 向线程 B 的 mWakeEventFd 写入数据,触发 epoll_wait() 返回,线程 B 退出休眠状态。
  • 消息处理
    线程 B 的 Looper 调用 MessageQueue.next() 取出消息,分发给对应的 Handler.handleMessage() 处理。
四、计划上风与性能考量


  • 线程隔离性

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

  • 高效性

    • 利用 epoll 和 eventfd 避免了忙等候(busy waiting),减少 CPU 空转。
    • 消息按时间排序,支持延时消息和优先级控制。

  • 低延迟与高吞吐

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

五、总结



  • 线程安全
    MessageQueue 通过 synchronized 锁保证多线程插入消息的安全性。
  • 高效唤醒
    结合 eventfd 和 epoll,在消息到达时精准唤醒目的线程,避免资源浪费。
  • 无缝跨线程通讯
    Handler 机制隐藏了底层复杂性,开发者只需通过 post() 或 sendMessage() 即可实现线程间通讯。
    1. +-------------------------------------------+
    2. |           Android Handler 机制            |
    3. |        基于 MessageQueue 和 Native 唤醒       |
    4. +-------------------------------------------+
    5. | [主线程] [UI操作] <--> |Handler|           |
    6. |                         | sendMessage()   |
    7. |                         ↓                 |
    8. |                  +--------------+         |
    9. |                  | MessageQueue |         |
    10. |                  | (同步锁保护)   |         |
    11. |                  +--------------+         |
    12. |                         | nativeWake()    |
    13. |                         ↓                 |
    14. |               [eventfd] → [epoll_wait]    |
    15. |                         ↑                 |
    16. |                  +--------------+         |
    17. |                  | 工作线程 Looper|        |
    18. |                  | (处理耗时任务) |        |
    19. +-------------------------------------------+
    复制代码
相干推荐

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


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

没腿的鸟

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表