Handler3 同步屏障
700 Words|Read in about 3 Min|本文总阅读量次
学习Handler之后,通常会出现同步屏障的字样。MessageQueue管理优先级队列的过程中,如果消息存在一种“紧急”消息, 需要更高的优先级处理,这个时候就需要同步屏障。
Handler3 同步屏障
开篇问题
1.为什么会存在同步屏障
2.如何去除同步屏障
3.同步屏障有啥用
什么是同步屏障
同步屏障就是阻碍同步消息,只让异步消息通过
Message分为3中:普通消息(同步消息)、屏障消息(同步屏障)和异步消息。我们通常使用的都是普通消息,而屏障消息就是在消息队列中插入一个屏障,在屏障之后的所有普通消息都会被挡着,不能被处理。不过异步消息却例外,屏障不会挡住异步消息,因此可以这样认为:屏障消息就是为了确保异步消息的优先级,设置了屏障后,只能处理其后的异步消息,同步消息会被挡住,除非撤销屏障。
注:没有同步屏障,不区分同步消息和异步消息,都属于一般消息按时间优先级来发送
如何发送异步消息
1Message message = Message.obtain();
2message.setAsynchronous(true);
3handler.sendMessage(message);
同步屏障原理
开启同步屏障
1MessageQueue.java#postSyncBarrier()
2/*
3 * @hide
4 */
5public int postSyncBarrier() {
6 return postSyncBarrier(SystemClock.uptimeMillis());
7}
8
9private int postSyncBarrier(long when) {
10 // Enqueue a new sync barrier token.
11 // We don't need to wake the queue because the purpose of a barrier is to stall it.
12 synchronized (this) {
13 final int token = mNextBarrierToken++;//类似句柄,用于管理当前的屏障的唯一标识
14 //此处跟Handler.enqueueMessage区别是这里没有msg.target
15 final Message msg = Message.obtain();
16 msg.markInUse();
17 msg.when = when;
18 msg.arg1 = token;
19
20 Message prev = null;
21 Message p = mMessages;
22 //将屏障根据时间插入链表动作
23 //开启同步屏障时间T不为0,且当前的同步消息里有时间小于T,则prev也不为null
24 if (when != 0) {
25 while (p != null && p.when <= when) {
26 prev = p;
27 p = p.next;
28 }
29 }
30 if (prev != null) { // invariant: p == prev.next
31 msg.next = p;
32 prev.next = msg;
33 } else {
34 msg.next = p;
35 mMessages = msg;
36 }
37 return token;
38 }
39}
开始对消息同步屏障
1MessageQueue.java#next()
2Message next() {
3 ...
4 for (;;) {
5 ...
6 //nextPollTimeoutMillis
7 //1.取值为-1,一直阻塞不会超时,mMessages为空,知道下一次唤醒
8 //2.取值为0,不会阻塞,当前时间和下一个消息时间相同,立即处理
9 //3.取值为大于0,最长阻塞为nextPollTimeoutMillis(超时机制),一般是当前时间早于下一个消息
10 nativePollOnce(ptr, nextPollTimeoutMillis);
11
12 synchronized (this) {
13 // Try to retrieve the next message. Return if found.
14 final long now = SystemClock.uptimeMillis();
15 Message prevMsg = null;
16 Message msg = mMessages;
17 //同步屏障起作用
18 //判断除了第一个同步屏障之后的第一个非同步消息出现,退出循环
19 if (msg != null && msg.target == null) {
20 // Stalled by a barrier. Find the next asynchronous message in the queue.
21 do {
22 prevMsg = msg;
23 msg = msg.next;
24 } while (msg != null && !msg.isAsynchronous());
25 }
26 if (msg != null) {
27 //同步消息和异步消息都需要判断是否需要设置阻塞时间
28 if (now < msg.when) {
29 // Next message is not ready. Set a timeout to wake up when it is ready.
30 //用于计算上面的下一循环nativePollOnce阻塞时间
31 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
32 } else {
33 // Got a message.
34 mBlocked = false;
35 //删除节点操作
36 if (prevMsg != null) {
37 prevMsg.next = msg.next;
38 } else {
39 mMessages = msg.next;
40 }
41 msg.next = null;
42 if (DEBUG) Log.v(TAG, "Returning message: " + msg);
43 msg.markInUse();
44 return msg;
45 }
46 } else {
47 // No more messages.
48 //用于复位,没有消息,等待下一次唤醒
49 nextPollTimeoutMillis = -1;
50 }
51 ...
52 }
53}
关闭/移除同步屏障
1MessageQueue.java#removeSyncBarrier()
2/*
3 * @hide
4 */
5//token为上述说明用于管理当前的屏障的唯一标识
6public void removeSyncBarrier(int token) {
7 // Remove a sync barrier token from the queue.
8 // If the queue is no longer stalled by a barrier then wake it.
9 synchronized (this) {
10 Message prev = null;
11 Message p = mMessages;
12 //找到当前屏障
13 while (p != null && (p.target != null || p.arg1 != token)) {
14 prev = p;
15 p = p.next;
16 }
17 if (p == null) {
18 throw new IllegalStateException("The specified message queue synchronization "
19 + " barrier token has not been posted or has already been removed.");
20 }
21 final boolean needWake;
22 //从链表中移除
23 if (prev != null) {
24 prev.next = p.next;
25 needWake = false;
26 } else {
27 mMessages = p.next;
28 needWake = mMessages == null || mMessages.target != null;
29 }
30 //Message的sPool对象池回收消息
31 p.recycleUnchecked();
32
33 // If the loop is quitting then it is already awake.
34 // We can assume mPtr != 0 when mQuitting is false.
35 //移除屏障,开始唤醒
36 if (needWake && !mQuitting) {
37 nativeWake(mPtr);
38 }
39 }
40}
用途
Android-Choreographer工作原理
问题回答
1.为什么会存在同步屏障
2.如何去除同步屏障
3.同步屏障有啥用
参考文献
[1] maove, Handler机制——同步屏障, 2019.
[2] willwaywang6, Android筑基——可视化方式理解 Handler 的同步屏障机制, 2020.
[3] 苍耳叔叔, Android-Choreographer工作原理, 2020.