简单理解
异步消息相比同步消息要优先执行,好比 :
当一堆人在排队进周杰伦演唱会时候,周杰伦来了,就通知保安,周杰伦来了,于是优先给周杰伦进去,等周杰伦进去后,其他人再按顺序进去
专业解释就是:
当开启了同步障碍时,Looper在获取下一个要执行的消息时,会在链表中寻找第一个要执行的异步消息,如果没有找到异步消息,就让当前线程沉睡。
nativeWake()方法和nativePollOnce()方法采用了Linux的epoll机制,其中nativePollOnce()的第二个值,当它是-1时会一直沉睡,直到被主动唤醒为止,当它是0时不会沉睡,当它是大于0的值时会沉睡传入的值那么多的毫秒时间。epoll机制实质上是让CPU沉睡,来保障当前线程一直在运行而不中断或者卡死,这也是Looper#loop()死循环为什么不会导致住县城ANR的根本原因。
Android 中异步消息应用场景:
在ViewRootImpl.java中有使用它:
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 开启当前Handler的同步屏障
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 发送一条异步消息
mChoreographer.postCallback(..., mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
cheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
这里的
Handler
使用的是主线程的
Looper
,因此这里会阻断主线程
Looper
的其他同步消息,在
ViewRootImpl
和
Choreographer
中多次使用到了异步消息,以完成
View
的整个绘制流程。
停止一个 HandlerThread
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
long wallStart = 0;
long threadStart = 0;
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
}
msg.target.dispatchMessage(msg);
public void quit() {
Message msg = Message.obtain();
// NOTE: By enqueueing directly into the message queue, the
// message is left with a null target. This is how we know it is
// a quit message.
mQueue.enqueueMessage(msg, 0);
}
mHandlerThread.getLooper().quit();
参考链接
- Android筑基——可视化方式理解 Handler 的同步屏障机制
- 每日问答 Handler应该是大家再熟悉不过的类了,那么其中有个同步屏障机制,你了解多少呢?
- Android Handler 源码分析
- 揭秘 Android 消息机制之同步屏障:target==null ?
- 终止Android中HandlerThread的方法
- Android消息机制Message的target==null的黑科技