美文网首页
Handler消息机制之深入理解Message.obtain()

Handler消息机制之深入理解Message.obtain()

作者: 中v中 | 来源:发表于2021-02-08 16:52 被阅读0次

    前言:在我们日常开发工作中,难免经常会在线程间进行消息传递,而这个过程最常用的实现方式就是Handler消息机制。当然,这并不我们今天的重点,今天我们要重点关注的是消息传递的中间体:Message。我们怎么去获取Message对象?可能大多数同学直接通过 new Message() 的方式创建一个新的对象;对性能和效率有了解的同学可能就会通过 handler.obtainMessage()Message.obtain() 的方式去得到这个Message对象。这几种方式有什么不同?效率和性能有什么差异?看到这里,你还是一脸懵b??是的话,就跟着我的思路继续看下去;如果你还有一副胸有成竹的感觉,我只能说:大佬,小弟给你递茶!!话不多说,切入正题。

    • Message创建方式一:Message message = new Message()
      这种方法很常见,就是常见的创建对象的方式。每次需要Message对象的时候都创建一个新的对象,每次都要去堆内存开辟对象存储空间,对象使用完后,jvm又要去对这个废弃的对象进行垃圾回收。看到这里,你可能会说:我们平时使用对象不都是这样的嘛,有什么大惊小怪的?难道我们平时操作对象的方式都存在效率和性能的问题?

      面对大家的各种质疑,我只想说:先喝杯咖啡冷静一下,听我给你娓娓道来!!俗话说:没有对比,就没有伤害。我们平时使用的方式并没有什么问题,只是这里有效率更高的获取方式。

    • Message创建方式二:Message message = handler.obtainMessage()
      上面说到,这种方式去获取Message,效率会更高!但是,何以见得??别急,下面我们从源码的角度为大家一一解析。先看handler.obtainMessage()的源码:

     public final Message obtainMessage()
        {
            return Message.obtain(this);
        }
    
    

    因为obtainMessage方法是Handler类的方法,因此这里的this指代的是调用obtainMessage方法的那个Handler:即handler.obtainMessage()中的handler对象。对this还有不清楚的,请移步 this用法详解 查看详细讲解。接着看obtain方法源码:

     public static Message obtain(Handler h) {
            Message m = obtain();
            m.target = h;
            return m;
        }
    

    从源码可以看到,这里是通过Message类的内部方法obtain()去获取这个Message对象,这就和我们接下来要讲解的第三种方式Message.obtain()调用逻辑一样了,我们接下来详细分析。插入一句题外话:Message类中的target是一个Handler对象,主要用于后期消息的处理。欲知详情,请移步 Handler消息机制。接下来我们详解:Message.obtain()

    • Message创建方式三:Message message = Message.obtain()
      打开Message类的obtain方法,源码如下:
      public static Message obtain() {
            synchronized (sPoolSync) {
                if (sPool != null) {
                    Message m = sPool;
                    sPool = m.next;
                    m.next = null;
                    m.flags = 0; // clear in-use flag
                    sPoolSize--;
                    return m;
                }
            }
            return new Message();
        }
    

    看到这里,可能我们还只是一知半解。因为方法里面有几个关键变量在迷惑我们,先弄清它们的含义,才能帮助我们更好的理解,接下来看一下这几个变量的定义:

        private static final Object sPoolSync = new Object();
        private static Message sPool;
        private static int sPoolSize = 0;
    

    没错,看到这里,理解起来就容易多了:

    1. sPoolSync :主要是给Message加一个对象锁,不允许多个线程同时访问Message类和obtain方法,保证获取到的sPool是最新的。
    2. sPool:存储我们循环利用Message的单链表。在Handler消息机制中说过Message的数据结构,因此这里sPool只是链表的头节点。
    3. sPoolSize:单链表的链表的长度,即存储的Message对象的个数。

    理解了这几个变量的涵义,对obtain方法的理解就更轻松了。对数据结构有了解的同学,一看obtain方法的实现逻辑就知道,它就是对链表的操作。具体逻辑如下:

    1. synchronized (sPoolSync):给对象加锁,保证同一时刻只有一个线程使用Message。
    2. if (sPool != null):判断sPool链表是否是空链表,如果是空,就直接创建一个Message对象返回;否则就进入第三步。
    3. 链表操作:将链表头节点移除作为重用的Message对象,第二个节点作为新链表(sPool )的头节点。
     Message m = sPool;
     sPool = m.next;
     m.next = null;
    
    具体操作如下图:
    
    
    这里写图片描述

    4.最后一步:链表的长度减一,把第三步得到的Message返回,用于重复利用,执行代码如下:

      sPoolSize--;
      return m;
    

    总结:这就是通过obtain方法获取Message对象的详情。通过obtain方法获取Message对象使得Message到了重复的利用,减少了每次获取Message时去申请空间的时间。同时,这样也不会永无止境的去创建新对象,减小了Jvm垃圾回收的压力,提高了效率。

    相关文章

      网友评论

          本文标题:Handler消息机制之深入理解Message.obtain()

          本文链接:https://www.haomeiwen.com/subject/decfxltx.html