不会阻塞之前的同步消息

如果插入的同步屏障,在中间位置,只有在同步屏障之前的消息执行完之后,同步屏障才会起作用.

同步屏障(Sync Barrier)只有在它之前的同步消息执行完之后,才会开始生效

我们可以从 MessageQueue 中插入同步屏障的逻辑来看其实际行为:

插入同步屏障逻辑(核心代码)

Message prev = null;
Message p = mMessages;
while (p != null && p.when <= when) {
    prev = p;
    p = p.next;
}
// 将同步屏障插入在 prev 和 p 之间
if (prev != null) {
    msg.next = p;
    prev.next = msg;
} else {
    msg.next = p;
    mMessages = msg;
}

这个逻辑说明:

• 插入的同步屏障会按时间顺序插入到队列中,通常是在一个合适的 when 时间点之后;

• 并不会把它放在消息队列的头部,而是会根据 when 找到它应有的位置。

所以:同步屏障的生效逻辑是这样的:

• MessageQueue 在查找下一个可执行的消息时,如果遇到了同步屏障,会:

跳过所有同步消息(target != null)

继续查找后面的异步消息(target == null)

• 如果找不到异步消息,就停止 dispatchMessage,从而让主线程“空转”并阻塞;

• 直到某个异步消息或者屏障被移除,主线程才恢复执行。

举个例子:

假设消息队列如下:

[同步A] → [同步B] → [屏障] → [同步C] → [异步D]

• 在屏障被插入到 B 和 C 之间的情况下,

• MessageQueue 处理完 A 和 B 后,到达“屏障”,开始只处理“异步”消息;

• 所以,C 会被屏蔽D 会被执行

• 如果 A 和 B 还没有执行完,屏障其实还未起作用。

结论:

只有在消息队列中,屏障之前的同步消息执行完后,屏障才会成为“当前首个待处理消息”,它才开始起作用。

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器