Looper、MessageQueue、Message及Handler的关系是什么?如何保证MessageQueue的并发访问安全?
更多面试题请看这里:https://interview.raoyunsoft.com/
核心组件关系
-
Message
消息的载体,包含任务数据和目标Handler信息。它在Handler机制中贯穿始终,本质是一个链表节点。 -
Handler
对外的操作接口,主要职责:- 生产者:通过
sendMessage()
/post()
向MessageQueue发送消息 - 处理器:在目标线程执行
handleMessage()
回调处理任务 - 内存管理:通过
obtain()
复用Message对象减少内存分配
- 生产者:通过
-
MessageQueue
消息容器,本质是优先级队列(按when
时间排序)。核心能力:- 消息入队:
enqueueMessage()
- 消息出队:
next()
- 空闲任务管理:
addIdleHandler()
- 消息入队:
-
Looper
消息循环引擎,关键作用:- 消费者:通过
loop()
无限循环调用queue.next()
取消息 - 线程绑定:通过
ThreadLocal
实现线程单例 - 消息分发:调用
msg.target.dispatchMessage()
触发处理
- 消费者:通过
工作流程
并发安全实现机制
当多线程同时操作MessageQueue(生产者线程入队,Looper线程出队),通过同步锁+等待释放策略避免死锁:
关键代码实现
// 入队操作(生产者线程)
boolean enqueueMessage(Message msg, long when) {synchronized (this) { // 获取互斥锁// ... 消息插入队列逻辑if (needWake) nativeWake(ptr); // 唤醒Looper线程}return true;
}// 出队操作(Looper线程)
Message next() {for (;;) {nativePollOnce(ptr, timeout); // 释放CPU进入等待(不持有锁!)synchronized (this) { // 获取锁后操作队列// ... 查找可用Messageif (msg != null) return msg;}}
}
安全机制详解
-
锁分离设计
synchronized(this)
保护队列操作临界区nativePollOnce()
在同步块外部执行等待
-
避免死锁流程
-
Native层协作
nativePollOnce()
:通过Linux epoll机制释放CPUnativeWake()
:向eventfd写入数据触发唤醒
关键点:当队列为空时,Looper在
nativePollOnce()
中释放CPU资源并等待,此时不持有Java层锁,允许生产者线程随时入队新消息。唤醒后重新竞争锁执行出队操作。
典型应用场景
// 工作线程发送任务
new Thread(() -> {Message msg = handler.obtainMessage();msg.obj = "Data from worker";handler.sendMessage(msg); // 安全入队
}).start();// 主线程Handler处理
Handler handler = new Handler(Looper.getMainLooper()) {@Overridepublic void handleMessage(Message msg) {String data = (String) msg.obj;textView.setText(data); // 更新UI}
};
这种机制保证了跨线程通信的安全性和高效性,是Android事件驱动的核心基础。