万字复盘 Handler 中各式 Message 的使用和原理(2)

简介: 万字复盘 Handler 中各式 Message 的使用和原理(2)

异步执行 Message

1832b220aa754cd18c504acc7686a560.png

Handler 发送的 Message 都是同步的,意味着大家都按照 when 的先后进行排序,谁先到谁执行。


如果遇到优先级高的 Message 可以通过 FrontQueue 发送插队 Message即可。但如果是希望同步的队列停滞只执行指定 Message 的话,即 Message 异步执行,现有的 API 是不够的。


事实上 Android 提供了同步屏障的机制来实现这一需求,不过主要面向的是系统 App 或 系统,App 可以通过反射来使用。

通过异步 Handler 实现

除了一般使用的 Handler 构造函数以外,Handler 还提供了创建发送异步 Message 的专用构造函数。通过该 Handler 发送的 Message 或 Runnable 都是异步的。我们将其称为异步 Handler

// Handler.java
    @UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    @NonNull
    public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {
        if (looper == null) throw new NullPointerException("looper must not be null");
        if (callback == null) throw new NullPointerException("callback must not be null");
        return new Handler(looper, callback, true);
    }

我们启动一个 HandlerThread 来测试一下同步屏障的使用:分别构建一个普通 Handler异步 Handler

    private fun startBarrierThread() {
        val handlerThread = HandlerThread("Test barrier thread")
        handlerThread.start()
        normalHandler = Handler(handlerThread.looper) { msg ->
            Log.d(...)
            true
        }
        barrierHandler = Handler.createAsync(handlerThread.looper) { msg ->
            Log.d(...)
            true
        }
    }

启动 HandlerThread 并向两个 Handler 各发送一个 Message。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        startBarrierThread()
        testNormalMessage()
        testSyncBarrierByHandler()
    }
    private fun testNormalMessage() {
        sendMessageRightNow(normalHandler, 1)
    }
    private fun testSyncBarrierByHandler() {
        sendMessageRightNow(barrierHandler, 2)
    }

是异步 Handler 的 Message 先执行吗?非也,因为我们还没有通知 MessageQueue 建立同步屏障!

09-24 23:02:19.032 28113 28113 D MainActivity: onCreate()
09-24 23:02:19.150 28113 28141 D MainActivity: Normal handler message occurred & what:1
09-24 23:02:19.150 28113 28141 D MainActivity: Barrier handler message occurred & what:2

除了发送异步Handler 发送异步 Message 以外,需要通过反射事先建立起同步屏障。

注意:建立同步屏障必须早于需要屏蔽的同步 Message,否则无效,后面的原理会提及。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        startBarrierThread()
        // 建立一个同步屏障
        postSyncBarrier(barrierHandler.looper)
        testNormalMessage()
        testSyncBarrierByHandler()
    }
    private fun postSyncBarrier(looper: Looper) {
        Log.d(...)
        val method: Method = MessageQueue::class.java.getDeclaredMethod("postSyncBarrier")
        barrierToken = method.invoke(looper.queue) as Int
    }

这样子便可以看到,异步 Message 执行了,而且同步 Message 永远得不到执行。

09-24 23:11:36.176 28600 28600 D MainActivity: onCreate()
09-24 23:11:36.296 28600 28600 D MainActivity: Add sync barrier
09-24 23:11:36.300 28600 28629 D MainActivity: Barrier handler message occurred & what:2

原因在于建立的同步屏障尚未移除,永远只处理队列里的异步 Message。想要让同步 Message 恢复执行的话 remove 同步屏障即可,同样也需要反射!

我们在异步 Handler 执行结束后移除同步屏障。

    private fun startBarrierThread() {
        ...
        barrierHandler = Handler.createAsync(handlerThread.looper) { msg ->
            Log.d(...)
            // 移除同步屏障
            removeSyncBarrier(barrierHandler.looper)
            true
        }
    }
    fun removeSyncBarrier(looper: Looper) {
        Log.d(...)
        val method = MessageQueue::class.java
            .getDeclaredMethod("removeSyncBarrier", Int::class.javaPrimitiveType)
        method.invoke(looper.queue, barrierToken)
    }

可以看到同步 Message 恢复了。

09-24 23:10:31.533 28539 28539 D MainActivity: onCreate()
09-24 23:10:31.652 28539 28568 D MainActivity: Barrier handler message occurred & what:2
09-24 23:10:31.652 28539 28568 D MainActivity: Remove sync barrier
09-24 23:10:31.653 28539 28568 D MainActivity: Normal handler message occurred & what:1

通过异步 Message 实现

没有专用的异步 Handler 的时候,可以向普通 Handler 发送一个 isAsync 属性为 true 的 message,效果和异步 Handler 是一样的。当然这种方式仍旧需要建立同步屏障。

在原有的发送 Message 的函数里加入 isAsync 的重载参数。

    private fun sendMessageRightNow(handler: Handler, what: Int, isAsync: Boolean = false) {
        Message.obtain().let {
            it.what = what
            it.isAsynchronous = isAsync
            handler.sendMessage(it)
        }
    }

向普通 Handler 发送异步 Message。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        testNormalMessage()
        // 改用 Message 方式发送异步 Message
        testSyncBarrierByMessage()
    }
    private fun testSyncBarrierByMessage() {
        sendMessageRightNow(normalHandler, 2, true)
    }

同样记得在异步 Message 收到后移除同步屏障。

    private fun startBarrierThread() {
        ...
        normalHandler = Handler(handlerThread.looper) { msg ->
            Log.d(...)
            if (2 == msg.what) removeSyncBarrier(barrierHandler.looper)
            true
        }
    }

结果和异步 Handler 的方式一致。

09-24 23:58:05.801 29040 29040 D MainActivity: onCreate()
09-24 23:58:05.923 29040 29040 D MainActivity: Add sync barrier
09-24 23:58:05.923 29040 29070 D MainActivity: Normal handler message occurred & what:2
09-24 23:58:05.924 29040 29070 D MainActivity: Remove sync barrier
09-24 23:58:05.924 29040 29070 D MainActivity: Normal handler message occurred & what:1

原理

先来看一下同步屏障是怎么建立的。

// MessageQueue.java
  // 默认是调用的时刻开始建立屏障
  public int postSyncBarrier() {
        return postSyncBarrier(SystemClock.uptimeMillis());
    }
    // 同步屏障支持指定开始的时刻
  // 默认是调用的时刻,而 0 表示?
  private int postSyncBarrier(long when) {
        synchronized (this) {
            // 同步屏障可以建立多个,用计数的 Token 变量识别
            final int token = mNextBarrierToken++;
            // 获取一个屏障 Message
            // 其 target 属性为空
            // 指定 when 属性为屏障的开始时刻
            final Message msg = Message.obtain();
            msg.markInUse();
            msg.when = when;
            // 将 Token 存入屏障 Message
            // 用以识别对应的同步屏障
            msg.arg1 = token;
            // 按照 when 的先后
            // 找到屏障 Message 插入队列的适当位置
            // 所以,如果同步屏障的建立调用得晚
            // 那么在它之前的 Message 无法阻拦
            Message prev = null;
            Message p = mMessages;
            if (when != 0) {
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
            }
            // 将屏障 Message 插入
            if (prev != null) {
                msg.next = p;
                prev.next = msg;
            } else {
                // 如果队列尚无 Message
                // 或队首的 Message 时刻
                // 都比屏障 Message 要晚的话
                // 将屏障 Message 插入队首
                msg.next = p;
                mMessages = msg;
            }
            // 返回上面的 Token 给调用端
            // 主要用于移除对应的屏障
            return token;
        }
    }

再来看下异步 Message 如何执行。

// MessageQueue.java
  Message next() {
        ...
        for (;;) {
            nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                // 队首是屏障 Message 的话
                // 遍历找到下一个异步 Message
                if (msg != null && msg.target == null) {
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                // 没有建立同步屏障且队里有 Message
                // 或者
                // 建立了同步屏障下且找到了异步 Message
                if (msg != null) {
                    // 如果当前时间尚早于目标执行时刻
                    if (now < msg.when) {
                        // 更新下次循环应当休眠的超时时间
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        mBlocked = false;
                        // Message 找到了并出队
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        // Message 返回
                        msg.next = null;
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // 队里尚无 Message
                    // 或建立了同步屏障,但尚无异步 Message
                    // 无限休眠
                    nextPollTimeoutMillis = -1;
                }
                ...
            }
            ...
            pendingIdleHandlerCount = 0;
            nextPollTimeoutMillis = 0;
        }
    }

最后看一下同步屏障如何移除。

// MessageQueue.java
  // 需要传入 add 时返回的 Token
  public void removeSyncBarrier(int token) {
        synchronized (this) {
            Message prev = null;
            Message p = mMessages;
            // 遍历队列直到找到 token 吻合的屏障 Message
            while (p != null && (p.target != null || p.arg1 != token)) {
                prev = p;
                p = p.next;
            }
            // 如果没找到会抛出异常
            if (p == null) {
                throw new IllegalStateException("The specified message queue synchronization "
                        + " barrier token has not been posted or has already been removed.");
            }
            final boolean needWake;
            // 将屏障 Message 移除
            // 如果屏障 Message 不在队首的话
            // 无需唤醒
            if (prev != null) {
                prev.next = p.next;
                needWake = false;
            } else {
                // 屏障 Message 在队首
                // 且新的队首存在且不是另一个屏障的话
                // 需要立即唤醒
                mMessages = p.next;
                needWake = mMessages == null || mMessages.target != null;
            }
            p.recycleUnchecked();
            // 唤醒以立即处理后面的 Message
            if (needWake && !mQuitting) {
                nativeWake(mPtr);
            }
        }
    }

对原理进行简单的总结:


同步屏障的建立:按照调用的时刻 when 在合适的位置放入一个屏障 Message(target 属性为 null)来实现,同时得到标识屏障的计数 token 存入屏障 Message

读取队列的时候发现存在屏障 Message 的话,会遍历队列并返回最早执行的异步 Message

同步屏障的移除:按照 token 去队列里找到匹配的屏障 Message 进行出队操作,如果出队后队首存在 Message 且非另一个同步屏障的话,立即唤醒 looper 线程

结论和应用

结论:


可以通过异步 Handler,也可以通过异步 Message 两种方式向 MessageQueue 添加异步 Message

但都需要事先建立同步屏障,屏障的建立时间必须在阻拦的 Message 发出之前

可以建立多个同步屏障,将按照指定的时刻排队,通过计数 Token 进行识别

同步屏障使用完之后记得移除,否则后续的 Message 永远阻塞

和插队执行 Message 的区别:


    插队 Message 只能确保先执行,完了后续的 Message 还得执行

异步 Message 则不同,同步屏障一旦建立将保持休眠,直到异步 Message 抵达。只有同步屏障被撤销,后续 Message 才可恢复执行

应用:


AOSP 系统中使用异步 Message 最典型的地方要属屏幕刷新,刷新的 Message 不希望被主线程的 Message 队列阻塞,所以在发送刷新 Message 之前都会建立一个同步屏障,确保刷新任务优先执行。

// ViewRootImpl.java
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
  final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }

屏障建立之后发送异步 Message。

// Choreographer.java
  private void postCallbackDelayedInternal(...) {
        synchronized (mLock) {
            ...
            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }

IdleHandler ”Message“

1832b220aa754cd18c504acc7686a560.png

MessageQueue 提供的 IdleHandler 可以让队列在空闲的时候回调(queueIdle())指定的逻辑,它本质上不是 Message 类型,但它在 MessageQueue 里调度的时候类似于 Message 的逻辑,姑且将它也理解成一种特殊的 ”Message“。


使用上很简单,调用 MessageQueue 的 addIdleHandler() 添加实现即可,执行完之后无需再度执行的话需要调用 removeIdleHandler() 移除,或在回调里返回 false。

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        testIdleHandler()
    }
    private fun testIdleHandler() {
        Log.d("MainActivity","testIdleHandler() start")
        mainHandler.looper.queue.addIdleHandler {
            Log.d("MainActivity", "testIdleHandler() queueIdle callback")
            false
        }
        Log.d("MainActivity","testIdleHandler() end ")
    }

可以看到 addIdleHandler 调用之后并没有立即执行,而是过了几百 ms,queueIdle() 才得到了执行。

09-23 22:56:46.130  7732  7732 D MainActivity: onCreate()
09-23 22:56:46.281  7732  7732 D MainActivity: testIdleHandler() start
09-23 22:56:46.281  7732  7732 D MainActivity: testIdleHandler() end
09-23 22:56:46.598  7732  7732 D MainActivity: testIdleHandler() queueIdle callback

如果在 addIdleHandler 调用之后接着发送一串非延时 Message,queueIdle() 是先执行还是后执行呢?

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        testIdleHandler()
        testSendMessages()
    }

结果显示一堆 Message 执行完了之后,仍旧过了几百 ms,queueIdle() 才得到了执行。

09-23 23:07:50.639  7926  7926 D MainActivity: onCreate()
09-23 23:07:50.856  7926  7926 D MainActivity: testIdleHandler() start
09-23 23:07:50.856  7926  7926 D MainActivity: testIdleHandler() end
09-23 23:07:50.856  7926  7926 D MainActivity: startSendMessage() start
09-23 23:07:50.857  7926  7926 D MainActivity: startSendMessage() end
09-23 23:07:50.914  7926  7926 D MainActivity: Main thread message occurred & what:1
...
09-23 23:07:50.916  7926  7926 D MainActivity: Main thread message occurred & what:10
09-23 23:07:51.132  7926  7926 D MainActivity: testIdleHandler() queueIdle callback

上述结果也可以理解,MessageQueue 里仍有一堆 Message 等待处理,并非空闲状态。所以需要执行完之后才有机会回调 queueIdle() 。

那如果发送的是延时 Message 呢?

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    testIdleHandler()
    testSendDelayedMessages()
}

因为发送的是延时 Message,MessageQueue 暂时是空闲的,会先将 IdleHandler 取出来处理。

09-23 23:21:36.135  8161  8161 D MainActivity: onCreate()
09-23 23:21:36.339  8161  8161 D MainActivity: testIdleHandler() start
09-23 23:21:36.340  8161  8161 D MainActivity: testIdleHandler() end
09-23 23:21:36.340  8161  8161 D MainActivity: testSendDelayedMessages() start
09-23 23:21:36.340  8161  8161 D MainActivity: testSendDelayedMessages() end
09-23 23:21:36.729  8161  8161 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:21:38.844  8161  8161 D MainActivity: Main thread message occurred & what:1
...
09-23 23:21:38.845  8161  8161 D MainActivity: Main thread message occurred & what:10

上面的 queueIdle() 返回了 false 确保处理后 Handler 得到了移除。

但如果返回 true 且没有调用 removeIdleHandler() 的话,后续空闲的时候 Handler 还会被执行,这点需要留意!

    private fun testIdleHandler() {
        mainHandler.looper.queue.addIdleHandler {
            ...
            true // false
        }
    }

queueIdle() 因为没被移除的缘故被回调了多次,源自于 Looper 没执行完一次 Message 后发现尚无 Message 的时候都会回调一遍 IdleHandler,直到队列一直没有 Message 到来。

09-23 23:24:04.765  8226  8226 D MainActivity: onCreate()
09-23 23:24:05.010  8226  8226 D MainActivity: testIdleHandler() start
09-23 23:24:05.011  8226  8226 D MainActivity: testIdleHandler() end
09-23 23:24:05.368  8226  8226 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:24:05.370  8226  8226 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:24:05.378  8226  8226 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:24:05.381  8226  8226 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:24:05.459  8226  8226 D MainActivity: testIdleHandler() queueIdle callback

那如果 add 完不移除的 IdleHandler 之后,发送一个延时 Message,那便会导致空闲消息多执行一遍。

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    testIdleHandler()
    sendDelayedMessage(mainHandler, 1)
}
09-23 23:31:53.928  8620  8620 D MainActivity: onCreate()
09-23 23:31:54.042  8620  8620 D MainActivity: testIdleHandler() start
09-23 23:31:54.042  8620  8620 D MainActivity: testIdleHandler() end
09-23 23:31:54.272  8620  8620 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:31:54.273  8620  8620 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:31:54.278  8620  8620 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:31:54.307  8620  8620 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:31:54.733  8620  8620 D MainActivity: testIdleHandler() queueIdle callback
09-23 23:31:56.546  8620  8620 D MainActivity: Main thread message occurred & what:1
09-23 23:31:56.546  8620  8620 D MainActivity: testIdleHandler() queueIdle callback

为什么?

queueIdle() 的回调由 MessageQueue#next() 回调。

// MessageQueue.java
  Message next() {
        ...
        // 循环的初次将待处理 IdleHandler 计数置为 -1
        // 保证第一次可以检查 Idle Handler 的存在和调用
        int pendingIdleHandlerCount = -1;
        int nextPollTimeoutMillis = 0;
        for (;;) {
            ...
            nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                // 队首的 Message 且建立了同步屏障的话,寻找下一个异步 Message
                if (msg != null && msg.target == null) {
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                // 找到了合适的 Message
                if (msg != null) {
                    // 如果当前时间尚早于目标执行时刻
                    // 设置休眠的超时时间,即当前时间与目标时刻的差值
                    if (now < msg.when) {
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        mBlocked = false;
                        // 时间条件满足 Message 出队
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        // 并返回 Message
                        msg.next = null;
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // 队里尚无合适的 Message
                    // 进入无限休眠
                    nextPollTimeoutMillis = -1;
                }
                // 如果正在退出 Looper,结束循环并返回 null
                // 将促使 loop() 退出
                if (mQuitting) {
                    dispose();
                    return null;
                }
                // 如果没有合适的 Message 且 Looper 没有退出
                // 检查是否有 Idle Handler 需要处理
                // 读取 Idle Handler 列表
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                // 如果暂时没有 Idle Handler 需要处理,则进入下一次循环
                // 为使下次循环如果出现新的 Idle Handler 能有机会执行
                // 不重置计数器,仍为初始值 -1
                if (pendingIdleHandlerCount <= 0) {
                    mBlocked = true;
                    continue;
                }
                // 如果 IdleHandler 存在则拷贝到待处理列表
                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }
            // 遍历待处理 Idle Handlers
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null;
                boolean keep = false;
                try {
                    // 逐个回调 queueIdle()
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }
                // 回调返回 false,则将其移除出 Idle 列表
                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }
            // 处理完之后重置 IdleHandler 的计数
            // 保证下次循环不会重复处理 IdleHandler
            pendingIdleHandlerCount = 0;
            nextPollTimeoutMillis = 0;
        }
    }

有几点细节需要留意:


next() 循环的第一次将 count 置为 -1,确保队列空闲的时候必然有机会处理 IdleHandler

如果暂无 IdleHandler 可以处理直接进入下一次循环,并且保留 count 的处置,确保下次循环可以检查是否有新的 IdleHandler 加入进来

IdleHandler 正常处理结束之后,避免下次循环重复处理,会将 count 置为 0,保证下次不再检查。注意:是下次循环,不是永久不检查

结论和应用

结论:

IdleHandler 可以实现 MessageQueue 空闲状态下的任务执行,比如做一些启动时的轻量级初始化任务。但由于其执行的时机依赖于队列的 Message 状态,不太可控,谨慎使用!


应用:AOSP 源码里有不少地方使用了 IdleHandler 机制,比如 ActivityThread 使用它在空闲的状态下进行 GC 回收处理。

// ActivityThread.java
  final class GcIdler implements MessageQueue.IdleHandler {
        @Override
        public final boolean queueIdle() {
            doGcIfNeeded();
            purgePendingResources();
            return false;
        }
    }
  void scheduleGcIdler() {
        if (!mGcIdlerScheduled) {
            mGcIdlerScheduled = true;
            Looper.myQueue().addIdleHandler(mGcIdler);
        }
        mH.removeMessages(H.GC_WHEN_IDLE);
    }
    void unscheduleGcIdler() {
        if (mGcIdlerScheduled) {
            mGcIdlerScheduled = false;
            Looper.myQueue().removeIdleHandler(mGcIdler);
        }
        mH.removeMessages(H.GC_WHEN_IDLE);
    }

名词总结

非延时、延时以及插队执行这几种 Message 大家使用较多,无需赘述。但其他几个冷僻的 Message 术语需要总结一下,供大家快速对比和加深理解。

1672155468263.png

结语

上述对于各种 Message 和 IdleHandler 做了演示和原理阐述,相信对于它的细节有了更深的了解。


下面来进行一个简单的总结:


非延时执行 Message:并非立即执行,而是按照请求的时刻进行排队和调度,最终取决于队列的顺序和主线程是否空闲

延时执行 Message:也并非在 Delay 的时刻立即执行,执行时刻受唤醒误差和线程任务阻塞的影响必然晚于 Delay 时刻

插队执行 Mesage:同样并非立即执行,而是每次都将任务放在了队首,达到先执行的目的,但打乱了执行顺序存在逻辑隐患

异步 Message:系统使用居多,App 则需反射,通过这种机制可插队执行同时确保其他 Message 阻塞,学习一下

IdleHandler “Message”:系统多有使用,实现 MessageQueue 空闲状态下的任务执行,但执行时机不可控,最好执行完之后便移除,谨慎使用


相关文章
|
10天前
|
前端开发 Java 程序员
面试官刁钻提问?轻松应对 break、continue 和 return 的巧妙用法
本次分享的主题是在面试break社招时被问到continue和return的区别与作用,面试官还刁钻的问了一些场景使用的坑点,小伙伴表示不太懂,现场有点慌。今天由我来给大家深入讲讲这三个关键词的区别和作用还会结合一些实战例子,保证你看完后不仅面试游刃有余,临时写代码也更得心应手,我们分为以下四部分。 1.了解背景铺垫的相关知识 2.Break、continue和return的定义 3.使用代码来实现三个关键字的逻辑 4.三个关键字在实践中应注意的坑点
|
2月前
|
Java 程序员
Java 面试高频考点:static 和 final 深度剖析
本文介绍了 Java 中的 `static` 和 `final` 关键字。`static` 修饰的属性和方法属于类而非对象,所有实例共享;`final` 用于变量、方法和类,确保其不可修改或继承。两者结合可用于定义常量。文章通过具体示例详细解析了它们的用法和应用场景。
39 3
|
7月前
|
存储 消息中间件 安全
27道 Handler 经典面试题,你能答出多少?
27道 Handler 经典面试题,你能答出多少?
|
5月前
|
消息中间件 前端开发 NoSQL
阿里面试:说说@Async实现原理?
阿里面试:说说@Async实现原理?
41 0
【面试题精讲】continuebreak和return的区别是什么
【面试题精讲】continuebreak和return的区别是什么
|
API 调度
万字复盘 Handler 中各式 Message 的使用和原理(1)
万字复盘 Handler 中各式 Message 的使用和原理(1)
万字复盘 Handler 中各式 Message 的使用和原理(1)
|
测试技术
软件测试面试题:遇到frame框架页面怎么处理?
软件测试面试题:遇到frame框架页面怎么处理?
182 0
|
消息中间件
一个 Handler 面试题引发的血案!!!
一个 Handler 面试题引发的血案!!!
119 0
|
Java 编译器 程序员
阿里面试官问Java中init和clinit区别,这么回答offer应该稳了
阿里面试官问Java中init和clinit区别,这么回答offer应该稳了
147 0
阿里面试官问Java中init和clinit区别,这么回答offer应该稳了
|
IDE Java 编译器
与面试官聊try-catch-finally关闭资源,你的答案还是10年前的?
与面试官聊try-catch-finally关闭资源,你的答案还是10年前的?
163 0