Handler系列四:同步屏障

331 阅读3分钟

Handler同步屏障是一种特殊的机制,用于在消息队列中临时阻塞同步消息(普通消息)的处理,同时允许异步消息继续执行。

一、定义与工作原理

同步屏障通过在MessageQueue中插入一个特殊的、没有目标Handler的消息(即target属性为null的消息)来实现。 这个屏障会阻止所有后续的同步消息被处理,直到屏障被移除。

二、应用场景

  1. 确保立即任务优先处理

    • 在需要优先执行某些紧急任务时,可以使用同步屏障暂时阻止其他消息的处理。
    • 例如,在绘制界面时,可能需要优先处理绘制消息以避免卡顿。
  2. 避免死锁和资源竞争

    • 在复杂的消息交互场景中,使用同步屏障可以防止因消息处理顺序不当引发的死锁或资源竞争。

四、识别同步消息和异步消息

在Android的MessageQueue中,消息(Message)分为同步消息(普通消息)和异步消息。这两种消息主要通过Message对象的isAsynchronous标志来区分:

  • 同步消息(普通消息):默认情况下,通过Handler发送的消息都是同步消息,即isAsynchronous标志为false。这些消息按照它们在消息队列中的顺序和时间戳进行处理。
  • 异步消息:异步消息是通过设置isAsynchronous标志为true来标识的。这类消息在消息队列中具有更高的优先级,可以越过同步屏障被优先处理。

五、设置同步屏障

同步屏障通过在MessageQueue中插入一个特殊的、没有目标Handler的消息(即target属性为null的消息)来实现。 这个屏障会阻止所有后续的同步消息被处理,直到屏障被移除。

1. 插入同步屏障

同步屏障的插入通常是通过MessageQueue的postSyncBarrier方法实现的, 但需要注意的是,这个方法在Android的SDK中是隐藏的(即标记为@hide),因此无法直接调用。 然而,可以通过反射或其他方式间接调用。

// 假设queue是已经获取的MessageQueue实例
// 注意:postSyncBarrier方法是私有的,这里仅为示例,实际使用中可能需要通过反射调用
int token = queue.postSyncBarrier(SystemClock.uptimeMillis());

postSyncBarrier方法会返回一个token,这个token在后续移除屏障时需要用到。

2. 消息队列处理逻辑

当MessageQueue在处理消息时,如果遇到target为null的消息(即同步屏障), 它会跳过所有后续的同步消息,直到找到一条异步消息或消息队列为空。 这个过程是通过MessageQueue的next方法实现的。

// MessageQueue的next方法大致逻辑(简化版)
Message next() {
    // ...
    for (;;) {
        // ...
        synchronized (this) {
            // ...
            if (msg != null && msg.target == null) {
                // 同步屏障,找到下一个异步消息
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            // ...
        }
        // ...
    }
}

六、移除同步屏障

同步屏障不会自动移除,因此在使用完毕后需要手动移除,否则会导致同步消息无法被处理。 移除屏障可以通过MessageQueue的removeSyncBarrier方法实现,并传入之前插入屏障时返回的token。

// 假设token是之前插入屏障时返回的token
queue.removeSyncBarrier(token);

七、总结

1、同步屏障,就是给MessageQueue发送一个target为null的消息(即同步屏障)

2、默认情况下Handler发送的都是同步消息,异步消息指isAsynchronous标志为true

3、同步屏障要手动移除