当前位置:   article > 正文

安卓消息机制中的消息队列MessageQueue的插入轮询算法_messagequeue 插入消息顺序

messagequeue 插入消息顺序

1.MessageQueue的插入算法

  1. boolean enqueueMessage(Message msg, long when) {
  2. if (msg.target == null) {
  3. throw new IllegalArgumentException("Message must have a target.");
  4. }
  5. if (msg.isInUse()) {
  6. throw new IllegalStateException(msg + " This message is already in use.");
  7. }
  8. synchronized (this) {
  9. if (mQuitting) {
  10. IllegalStateException e = new IllegalStateException(
  11. msg.target + " sending message to a Handler on a dead thread");
  12. Log.w("MessageQueue", e.getMessage(), e);
  13. msg.recycle();
  14. return false;
  15. }
  16. msg.markInUse();
  17. msg.when = when;
  18. Message p = mMessages;
  19. boolean needWake;
  20. if (p == null || when == 0 || when < p.when) {
  21. // New head, wake up the event queue if blocked.
  22. msg.next = p;
  23. mMessages = msg;
  24. needWake = mBlocked;
  25. } else {
  26. // Inserted within the middle of the queue. Usually we don't have to wake
  27. // up the event queue unless there is a barrier at the head of the queue
  28. // and the message is the earliest asynchronous message in the queue.
  29. needWake = mBlocked && p.target == null && msg.isAsynchronous();
  30. Message prev;
  31. for (;;) {
  32. prev = p;
  33. p = p.next;
  34. if (p == null || when < p.when) {
  35. break;
  36. }
  37. if (needWake && p.isAsynchronous()) {
  38. needWake = false;
  39. }
  40. }
  41. msg.next = p; // invariant: p == prev.next
  42. prev.next = msg;
  43. }
  44. // We can assume mPtr != 0 because mQuitting is false.
  45. if (needWake) {
  46. nativeWake(mPtr);
  47. }
  48. }
  49. return true;
  50. }

(1)当第一个消息到来时,此消息就是消息队列中的头消息。 mMessages  = msg;  mMessages  相当于头指针

无标题.png
(2)此后来的消息(假如消息的 when == 0或者小于头结点的when值 )都会作为头消息插入(msg1表示的是上一个消息,本次消息是msg)
    i执行 Message p =  mMessages ;后

无标题.png
   ii执行 msg.next = p;后
  无标题.png
  iii执行 mMessages  = msg;后

无标题.png
可以看到 mMessages 移动到了头部,新来的消息是从头部开始插入的,最后形成了一个单链表,方法执行完毕后p会被垃圾回收器回收
(3)若后面来的消息 when不等于0,或者when比头结点的 when大,即不满足 when == 0 || when < p.when。那么
走这段程序
  1. for (;;) {
  2. prev = p;
  3. p = p.next;
  4. if (p == null || when < p.when) {
  5. break;
  6. }
  7. if (needWake && p.isAsynchronous()) {
  8. needWake = false;
  9. }
  10. }
进入无限循环,想跳出循环只能执行break,执行 break的条件是 p ==  null  || when < p.when,即到了MessageQueue的最后一个节点(前面节点的when值都比要插入的when值小,否则满足 when < p.when会直接break掉 )或者找到某个节点的when值比要插入message的when值大。跳出循环后执行:
                  msg.next = p;  // invariant: p == prev.next
               prev.next = msg;
将msg插入pre和p节点之间

所以消息队列是基于一个过期时间先后顺序排序的,需要尽快处理的消息排在前面。
1.MessageQueue的轮询算法
MessageQueue的 next()方法中,有个无限循环,一直取消息
  1. 。。。。。。
  2. synchronized (this) {
  3. // Try to retrieve the next message. Return if found.
  4. final long now = SystemClock.uptimeMillis();
  5. Message prevMsg = null;
  6. Message msg = mMessages;
  7. if (msg != null && msg.target == null) {
  8. // Stalled by a barrier. Find the next asynchronous message in the queue.
  9. do {
  10. prevMsg = msg;
  11. msg = msg.next;
  12. } while (msg != null && !msg.isAsynchronous());
  13. }
  14. if (msg != null) {
  15. if (now < msg.when) {
  16. // Next message is not ready. Set a timeout to wake up when it is ready.
  17. nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
  18. } else {
  19. // Got a message.
  20. mBlocked = false;
  21. if (prevMsg != null) {
  22. prevMsg.next = msg.next;
  23. } else {
  24. mMessages = msg.next;
  25. }
  26. msg.next = null;
  27. if (false) Log.v("MessageQueue", "Returning message: " + msg);
  28. return msg;
  29. }
  30. } else {
  31. // No more messages.
  32. nextPollTimeoutMillis = -1;
  33. }
  34. // Process the quit message now that all pending messages have been handled.
  35. if (mQuitting) {
  36. dispose();
  37. return null;
  38. }
  39. // If first time idle, then get the number of idlers to run.
  40. // Idle handles only run if the queue is empty or if the first message
  41. // in the queue (possibly a barrier) is due to be handled in the future.
  42. if (pendingIdleHandlerCount < 0
  43. && (mMessages == null || now < mMessages.when)) {
  44. pendingIdleHandlerCount = mIdleHandlers.size();
  45. }
  46. if (pendingIdleHandlerCount <= 0) {
  47. // No idle handlers to run. Loop and wait some more.
  48. mBlocked = true;
  49. continue;
  50. }
  51. if (mPendingIdleHandlers == null) {
  52. mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
  53. }
  54. mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
  55. }
  56. 。。。。。。
一般 msg.target !=  null, 所以取消息一般走的是下面的代码:
      mMessages  = msg.next;
       msg.next =  null ;
即取出头结点。因为消息队列是按照消息需要处理的时间进行排序的,所以取消息也就肯定会从消息队列的头开始。





声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/956931
推荐阅读
相关标签
  

闽ICP备14008679号