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.pswp.cn/news/898605.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/898605.shtml
英文地址,請注明出處:http://en.pswp.cn/news/898605.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

關于 2>/dev/null 的作用以及機理

每個進程都有三個標準文件描述符&#xff1a;stdin&#xff08;標準輸入&#xff09;、stdout&#xff08;標準輸出&#xff09;和stderr&#xff08;標準錯誤&#xff09;。默認情況下&#xff0c;stderr會輸出到終端。使用2>可以將stderr重定向到其他地方&#xff0c;比如…

MySQL中的鎖機制:從全局鎖到行級鎖

目錄 1. 鎖的基本概念 2. 全局鎖 2.1 全局鎖的定義 2.2 全局鎖的類型 2.3 全局鎖的使用場景 2.4 全局鎖的實現方式 2.5 全局鎖的優缺點 2.6 全局鎖的優化 3. 表級鎖 3.1 表級鎖的類型 3.2 表級鎖的使用場景 3.3 表級鎖的優缺點 4. 意向鎖&#xff08;Intention Lo…

編程語言選擇分析:C#、Rust、Go 與 TypeScript 編譯器優化

編程語言選擇分析&#xff1a;C#、Rust、Go 與 TypeScript 編譯器優化 在討論編程語言的選擇時&#xff0c;特別是針對微軟的 C# 和 Rust&#xff0c;以及谷歌的 Go 語言&#xff0c;以及微軟試圖通過 Go 來拯救 TypeScript 編譯器的問題&#xff0c;我們可以從多個角度來分析和…

基于WebRTC的嵌入式音視頻通話SDK:EasyRTC跨平臺兼容性技術架構實時通信的底層實現

EasyRTC的核心架構圍繞WebRTC技術構建&#xff0c;同時通過擴展信令服務、媒體服務器和NAT穿透機制&#xff0c;解決了WebRTC在實際部署中的痛點。其架構可以分為以下幾個核心模塊&#xff1a; 1&#xff09;WebRTC基礎層 媒體捕獲與處理&#xff1a;通過getUserMediaAPI獲取…

【Rust】包和模塊管理,以及作用域等問題——Rust語言基礎15

文章目錄 1. 前言2. 包和 Crate3. 定義模塊以及模塊之間的關系4. 作用域問題4.1. 作用域問題初現4.2. 解決問題一4.3. 解決問題二4.4. super 關鍵字4.5. 將路徑引入作用域4.6. as 關鍵字4.7. pub use 重導出 5. 引入的問題5.1. 引入一個外部包5.2. 嵌套路徑來消除大量的 use 行…

微服務架構中的API網關:Spring Cloud與Kong/Traefik等方案對比

微服務架構中的API網關&#xff1a;Spring Cloud與Kong/Traefik等方案對比 一、API 網關的概念二、API 網關的主要功能2.1 統一入口與路由轉發2.2 安全與權限控制2.3 流量管理與容錯2.4 API 管理與聚合2.5 監控與日志2.5 協議轉換與適配2.6 控制平面與配置管理 三、API 網關選型…

NewStar CTF web wp

文章目錄 week1headach3會贏嗎智械危機謝謝皮蛋PangBai 過家家&#xff08;1&#xff09; week3include meblindsql1臭皮的計算機臭皮踩踩背這照片是你嗎 week4Pangbai過家家四blindsql2chocolateezcmsssezpollute隱藏的密碼 weeek5pangbai過家家(5)redissqlshell臭皮吹泡泡臭皮…

Linux驅動開發-①中斷②阻塞、非阻塞IO和異步通知

Linux驅動開發-①中斷②阻塞、非阻塞IO和異步通知 一&#xff0c;中斷1.中斷的流程2.上半部和下半部2.1上半部2.2下半部2.2.1 tasklet2.2.2 工作隊列 3.按鍵延時消抖中斷程序 二&#xff0c;阻塞和非阻塞IO和異步通知1.阻塞IO1.1 常見結構11.2 常見結構2 2.非阻塞IO2.1 驅動結構…

Docker和Dify學習筆記

文章目錄 1 docker學習1.1 基本命令使用1.1.1 docker ps查看當前正在運行的鏡像1.1.2 docker stop停止容器1.1.3 docker compose容器編排1.1.4 docker網絡[1] 進入到容器里面敲命令[2] docker network ls[3] brige網絡模式下容器訪問宿主機的方式 2 Dify的安裝和基礎使用2.1 下…

高并發庫存系統是否適合使用 ORM(Hibernate / MyBatis)

在設計高并發的庫存管理系統時&#xff0c;數據層的選擇至關重要。許多企業開發中習慣使用 ORM&#xff08;如 Hibernate、MyBatis&#xff09;來簡化數據庫訪問&#xff0c;但在高并發、高吞吐的場景下&#xff0c;ORM 的適用性往往成為爭議焦點。本文將探討高并發庫存系統是否…

Web爬蟲利器FireCrawl:全方位助力AI訓練與高效數據抓取。本地部署方式

開源地址&#xff1a;https://github.com/mendableai/firecrawl 01、FireCrawl 項目簡介 Firecrawl 是一款開源、優秀、尖端的 AI 爬蟲工具&#xff0c;專門從事 Web 數據提取&#xff0c;并將其轉換為 Markdown 格式或者其他結構化數據。 Firecrawl 還特別上線了一個新的功…

探秘Transformer系列之(16)--- 資源占用

探秘Transformer系列之&#xff08;16&#xff09;— 資源占用 文章目錄 探秘Transformer系列之&#xff08;16&#xff09;--- 資源占用0x00 概述0x01 背景知識1.1 數據類型1.2 進制&換算數字進制存儲度量換算 1.3 參數顯存占用有參數的層無參數的層所需資源 1.4 計算量 0…

jaeger安裝和簡單使用

文章目錄 jaeger安裝和使用什么是jaegerjaeger安裝 jaeger安裝和使用 什么是jaeger 官網&#xff1a;https://www.jaegertracing.io/ Jaeger 是一個分布式追蹤系統。Jaeger的靈感來自 Dapper 和 OpenZipkin&#xff0c;是一個由 Uber 創建并捐贈給 云原生計算基金會&#xf…

【Mybatis-plus】在mybatis-plus中 if test標簽如何判斷 list不為空

博主介紹&#xff1a;?全網粉絲22W&#xff0c;CSDN博客專家、Java領域優質創作者&#xff0c;掘金/華為云/阿里云/InfoQ等平臺優質作者、專注于Java技術領域? 技術范圍&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大數據、物…

FRP在物聯網設備中的穿透方案

物聯網設備常位于NAT后&#xff0c;FRP為其提供穩定穿透鏈路。 配置要點 輕量化部署&#xff1a;使用ARM版本FRP客戶端&#xff0c;適配樹莓派等設備9。 自啟動腳本&#xff1a;通過systemd或crontab實現設備重啟后自動連接26。 低功耗優化&#xff1a;調整心跳間隔&#xf…

【遞歸,搜索與回溯算法篇】- 名詞解釋

一. 遞歸 1. 什么是遞歸&#xff1f; 定義&#xff1a; 函數自己調用自己的情況關鍵點&#xff1a; ?終止條件&#xff1a; 必須明確遞歸出口&#xff0c;避免無限遞歸 ?子問題拆分&#xff1a; 問題需能分解成結構相同的更小的子問題缺點&#xff1a; ?棧溢出風險&#x…

條件變量,鎖,共享數據的關系

條件變量、共享數據和鎖之間的三方耦合關系源于多線程環境下對資源訪問的同步需求。以下是關鍵點分析&#xff1a; 條件變量中通常會對共享數據進行判斷和處理&#xff0c;如果不加鎖就會出現數據競爭的問題&#xff0c;所以并不是條件變量要跟鎖一起使用&#xff0c;而是上鎖為…

大屏技術匯集【目錄】

Cesium 自從首次發布以來&#xff0c;經歷了多個版本的迭代和更新&#xff0c;每個版本都帶來了性能改進、新功能添加以及對現有功能的優化。以下是 Cesium 一些重要版本及其主要特點&#xff1a; 主要版本概述 Cesium 1.0 (2012年) 初始版本發布&#xff0c;確立了Cesium作為…

圖解AUTOSAR_CP_EEPROM_Abstraction

AUTOSAR EEPROM抽象模塊詳細說明 基于AUTOSAR標準的EEPROM抽象層技術解析 目錄 1. 概述 1.1 核心功能1.2 模塊地位2. 架構概覽 2.1 架構層次2.2 模塊交互3. 配置結構 3.1 主要配置容器3.2 關鍵配置參數4. 狀態管理 4.1 基本狀態4.2 狀態轉換5. 接口設計 5.1 主要接口分類5.2 接…

C++相關基礎概念之入門講解(下)

1. 引用 ? int main() {const int a10;int& aaa;aa;cout<<aa<<endl; } 引用 不是新定義一個變量&#xff0c;而 是給已存在變量取了一個別名 &#xff0c;編譯器不會為引用變量開辟內存空 間&#xff0c;它和它引用的變量 共用同一塊內存空間&#xff08;初…