美文网首页
Handler机制

Handler机制

作者: 星宇V | 来源:发表于2021-02-20 10:50 被阅读0次

    handler通信实现的方案实际上是一种内存共享的方案

    为什么线程间通信不会干扰,加了锁,内存管理设计的很完善

    • 通过loop.loop启动loop.就开始了一个死循环,循环去队列中进行取值
      loop取到一个为null的message,则会退出

    • handler发送消息,不管send post到最后,都会到sentMessageAtTime,在这个方法里面,调用到enqeueMessage.在这个方法内,接着走到了queue.enqeueMessage()这里会把时间穿进去
      这个方法内,会把消息插入队列中(排序算法:插入排序)。

    • messageQueue next方法,会返回message消息,相当于取消息的方法
      这个next的方法调用,会在looper里。在loop方法内,有个for死循环,在这里会调用queue.next方法。然后取出message后,在这里方法里,接着调用到了msg.target.diaptachMessage方法。
      在这个方法内,会走到handleMessage

    • 消息队列,messageQueue, 是一个优先级队列,由单链表实现的。 因为next取值的时候,默认取第一个,所以,他相当于先进先出的数据结构,也就是队列。

    Loop

    • 核心有三个 构造函数 loop ThreadLocal
    • Loop类里有个私有的构造函数,所以其初始化有prepare方法完成
      image.png
    • 所以说到loop的初始化,就必须说到ThreadLocal---他是一个线程上下文的存储变量.ThreadLocal本身是不存储数据的,他存储数据主要是因为内部的一个类ThreadLocalMap。


      image.png

      他存储数据是通过线程获取ThreadLocalMap。每一个线程都有一个ThreadLocalMap成员变量threadLocals
      一个线程里只有一个loop,就是根据threadLocal保证的

    ThreadLocal

    • ThreadLocal 里有一个静态内部类ThreadLocalMap。实际存储数据的东西是ThreadLocalMap,他里面维护一数组,并对ThreadLocal求模获得下标进行存储。
    • 而每个looper里有一个MessageQueue,所以,MessageQueue是跟looper绑定 ,所以也就是每个线程只有一个MessageQueue,并且其声明是final

    而且 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();因为是static final,所以这个变量在整个Android唯一

    handler内存泄漏的原因

    是因为生命周期的问题,所以并不仅仅是内部类持有外部类引用,而是因为他们声明周期不同。之所以生命周期不同,是因为在handler sendmessage的时候,执行到handler的enqueueMessage的msg.target赋值为了当前handler,这个队列的生命存在周期可能很长,所以导致handler释放不了,然后handler拿着外部的引用,导致了外部也无法释放

    子线程消息队列无消息后应该怎么做

    • 调用looper.quit方法,此时会处理掉什么消息,并唤醒消息队列的循环(无消息的时候会让他睡眠),然后因为给一个判断的变量mQuitting赋值为true了,所以在循环操作里,监测到这个true
       // Process the quit message now that all pending messages have been handled.
                    if (mQuitting) {
                        dispose();
                        return null;
                    }
    

    在此处messageQueue的next方法返回为null,

    
            for (;;) {
                Message msg = queue.next(); // might block
                if (msg == null) {
                    // No message indicates that the message queue is quitting.
                    return;
                }
    
    

    也就是Looper的loop方法里msg为null,然后就return了。

    • 所以quit方法做了什么事?---唤醒睡眠的线程(因消息为null睡眠了)--MessageQueue里mQuitAllowed设置为true ---导致next返回null--导致loop方法里得到null后return 退出

    为什么多个线程都可以往消息队列中放消息,是怎么保证线程安全的

    • 因为加锁了
       boolean enqueueMessage(Message msg, long when) {
              ...
          synchronized (this) {
              .....
          }
            .....
       }
    

    注意此处锁的是this,所以也就是对同一个这个对象的访问是有锁的,但是对不同对象是没事的,因为this不同
    为什么取消息的时候也有synchronized (this)------因为从这个队列中取的时候,有可能有其他消息要进来,而且可能会插队(比如同步屏障或者延时消息的插队)

    message的创建问题---大量new出来对象后为何不会内存抖动(full gc虽然会处理这些碎片,但是无法控制)和oom,其中涉及到了享元设计模式(内存复用,不是指的数据复用),在loop取出消息后,并没有直接将这个对象释放,而是msg.recycleUnchecked();

    相关文章

      网友评论

          本文标题:Handler机制

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