zoukankan      html  css  js  c++  java
  • Android 异步消息处理机制前篇(二):深入理解Message消息池

    版权声明:本文出自汪磊的博客,转载请务必注明出处。

    上一篇中共同探讨了ThreadLocal,这篇我们一起看下常提到的Message消息池到底是怎么回事,废话少说吧,进入正题。

    对于稍有经验的开发人员来说我们在使用Handler发送异步消息获取Message的时候都会使用如下代码获取一个Message对象:

    1 Message msg = mHandler.obtainMessage();

    而不是直接new一个:

    1 Message msg = new Message();

    二者的主要区别就是上面的用到缓存池概念,如果池中有闲着的则拿来用,没有则new一个Message。后者则没有这个机制,直接new一个拿来用。

    接下来我们分析一下这个缓存池是怎么实现的。

    Message缓存池源码分析

    Handler中obtainMessage()方法实质还是调用的Message中obtain()方法,这里就直接看Message中obtain()方法源码了:

     1 public static Message obtain() {
     2         synchronized (sPoolSync) {
     3             if (sPool != null) {
     4                 Message m = sPool;
     5                 sPool = m.next;
     6                 m.next = null;
     7                 m.flags = 0; // clear in-use flag
     8                 sPoolSize--;
     9                 return m;
    10             }
    11         }
    12         return new Message();
    13  }

    第3行首先判断sPool是否为null,如果为null则直接执行12行直接new一个Message返回,整个方法结束,sPool是什么鬼?定义如下:

    1 private static Message sPool;

    看到了吧,就是一个Message对象,sPool其实就相当于一个头指针,指向缓存池中第一个缓存的Message,分析完所有就会自然明白了其作用。

    继续向下分析。

    sPool不为null则进入4-9行代码逻辑,sPool不为null说明缓存池中存在空闲的Message.

    第4行记录sPool,并且第9行返回m作为整个方法的返回值,也就是返回缓存池中的空闲Message供外部使用,不需要额外内存开销。

    第5行sPool指向下一个缓存对象。

    第6行m.next置为null,到这里最重要的逻辑就完了,也许你还蒙蔽呢,这是什么啊,其实很简单Message的缓存池其实就是用了一个数据结构-单向链表。

    接下来又要展示我强大的画图能力了,没有什么是一个图示不能解决的:

    假设此时缓存池中有三个空闲message:message1,message2,message3。sPool一开始指向头部message1。

    执行第4行代码相当于图中步骤①,没什么好解释的。

    执行第5行代码相当于图中步骤②,sPool指向下一个缓存message,此处为message2.

    执行第6行代码相当于图中步骤③,message1与message2断开连接。

    怎么样这样解释该明白了,其实本身就很简单。

    7,8行就是清除标记以及改变sPoolSize大小,sPoolSize用来记录缓存池中存在的元素个数,缓存池大小是有限制的,超过规定大小则不能再往里面添加。

    obtain()总结

    好了,到此主要逻辑就分析完了,obtain()主要逻辑就是先判断缓存池中是否存在空闲message,如果存在则返回头部message,并且指针指向下一个空闲message,然后头部的message与之后链表  断开连接。如果不存在空闲message则直接new一个直接返回。

    上面的逻辑都是从缓存池中获取的操作,那什么时候向缓存池中存放呢?我们继续向下分析。

    Message类中recycle()方法是用于回收用完的mesage,将此message会收到缓存池中,是这样的吗?我们看下源码就知道了:

     1 public void recycle() {
     2         if (isInUse()) {
     3             if (gCheckRecycle) {
     4                 throw new IllegalStateException("This message cannot be recycled because it "
     5                         + "is still in use.");
     6             }
     7             return;
     8         }
     9         recycleUnchecked();
    10 }

    recycle方法中主要判断当前message是否正在使用中,如果正在使用则抛出异常,没被使用则调用recycleUnchecked()方法,接下来看下recycleUnchecked():

     1 void recycleUnchecked() {
     2         // Mark the message as in use while it remains in the recycled object pool.
     3         // Clear out all other details.
     4         flags = FLAG_IN_USE;
     5         what = 0;
     6         arg1 = 0;
     7         arg2 = 0;
     8         obj = null;
     9         replyTo = null;
    10         sendingUid = -1;
    11         when = 0;
    12         target = null;
    13         callback = null;
    14         data = null;
    15 
    16         synchronized (sPoolSync) {
    17             if (sPoolSize < MAX_POOL_SIZE) {
    18                 next = sPool;
    19                 sPool = this;
    20                 sPoolSize++;
    21             }
    22         }
    23 }

    4-14主要就是清除一些当前标记。

    17行,MAX_POOL_SIZE就是规定的缓存池中最多缓存message的个数,如果当前已经存储的数量小于规定的最大缓存个数则继续向下执行。

    18,19行就是重点了,又到展示我强大画图能力的时候了,一张图解决:

    比如缓存池中链表中为message2,message3,sPool指向头部message2。

    此时,message1被回收执行recycle()操作。最终执行到recycleUnchecked()的18,19行逻辑。

    18行:相当于将图中message1的next指针指向sPool,此时sPool指向message2,也就是将message1与message2链接,也就是图中①操作。

    19行:sPool重新定位到当前被回收的message,这里也就是message1。相当于图中②操作

    recycle()总结

    好了,到这里回收就讲完了,最主要就是18,19行逻辑,recycle()最主要就是将当前message放入缓存池链表头部。

    到此,我想讲解的就完了,本篇核心就是数据结构中单项链表的实际应用,如果单向链表你很熟悉,我觉得这里应该很轻松的就理解了,即使不是很熟悉,用心思考一下也应该能理解,这里不难理解。

    本篇就到此为止了,下一篇Android异步消息处理机制完全解析。

  • 相关阅读:
    VUE单页模板
    Nacos(作为配置中心)
    OpenFeign与Nacos(作为注册中心) 远程调用
    Nacos 服务注册
    Docker 安装Redis
    Docker安装Mysql
    多线程之CAS和ABA
    Volatile
    JAVA语言的特点
    判断多选按钮被选中两种方法
  • 原文地址:https://www.cnblogs.com/leipDao/p/7850473.html
Copyright © 2011-2022 走看看