例子

同步屏障没用好会导致很严重的问题,如果某个子线程主动通过Choreographer来进行更新UI,但是由于某种原因导致放置的同步屏障未能remove掉,就会导致后续的所有同步任务都无法执行。之前就接触过一例问题,就是由于系统主线程的同步屏障未能正常被remove,从而导致了所有的系统功能(依赖于handler的同步任务)都无法正常调用,排查了好久才定位到是由于同步屏障的原因。  模拟下这个问题

模拟主线程插入同步屏障 + 没有移除,导致 Handler.post() 这样的同步任务永远不执行,但 UI invalidate() 仍然生效,绘制正常。

示例代码(重点放在“部分功能失效”而非“绘制失效”)

public class SyncBarrierDemoActivity extends AppCompatActivity {

    private int barrierToken = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView tv = new TextView(this);
        tv.setText("点击我插入同步屏障,然后再试试按钮");
        tv.setTextSize(20);
        setContentView(tv);

        tv.setOnClickListener(v -> {
            Log.d("SyncTest", "点击事件触发");
            insertSyncBarrier(); // ❗插入但不移除
            v.setText("已插入同步屏障");

            // 异步注册一次 invalidate
            v.postDelayed(() -> {
                Log.d("SyncTest", "尝试更新文本(postDelayed)");
                v.setText("这行永远不会出现!");
            }, 3000);
        });
    }

    private void insertSyncBarrier() {
        try {
            MessageQueue queue = Looper.getMainLooper().getQueue();
            Method postSyncBarrier = MessageQueue.class.getDeclaredMethod("postSyncBarrier");
            postSyncBarrier.setAccessible(true);
            barrierToken = (int) postSyncBarrier.invoke(queue);
            Log.d("SyncTest", "同步屏障插入成功 barrierToken=" + barrierToken);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

模拟效果:

项目 是否执行 原因
setOnClickListener 响应 ✅ 会 是 UI 主线程执行的回调,不依赖 Handler
invalidate()、重绘 View ✅ 会 最终通过 Choreographer 异步驱动
Handler.postDelayed() ❌ 不会 默认是同步消息,被同步屏障阻塞了!
Toast.show() / Dialog ❌ 不会 系统内部使用 Handler,同样阻塞

如果你要模拟“彻底死锁 UI”,需要:

你必须主动移除 Choreographer 的异步注册回调(即 doFrame() 不再注册),或在特殊时机提前插入屏障阻止它注册。

这在现实中几乎不会发生,除非你故意干坏事,或者某些框架用了危险的反射 +屏障逻辑。

最终结论

错误说法(我之前) 正确修正
插入屏障会导致 UI 卡死 ❌ UI 绘制流程是异步驱动,不会死
invalidate() 会失效 ❌ 不会失效,会照常触发重新绘制
所有消息都卡住了 ❌ 只有同步消息,如 post() / postDelayed() 被卡

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