目錄
一、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
?中取出消息處理。
三、完整流程:跨線程通信的步驟分解
-
發送消息:
線程 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()
?即可實現線程間通信。 -
+-------------------------------------------+ | 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