美文网首页
FW-Handler

FW-Handler

作者: 挖打发 | 来源:发表于2021-04-28 22:12 被阅读0次

    问题1 子线程里可以创建Handler吗

    子线程里没prepare looper时创建Handler会抛出RuntimeException,prepare looper后可以创建

    查看Handler构造函数,因为获得的looper为空,所以才抛出上面的异常

    怎样获得Looper呢?通过prepare创建,looper保存在ThreadLocal中,quiteAllowed参数代表Looper是否可以退出,子线程调用prepare()时是允许退出的,下面的prepareMainLooper是主线程创建looper时调用,不允许looer退出

    然后消息队列是在looper中创建的

    总体结构:一个线程对应一个Looper,一个Looper对应一个MessageQueue,一个Looper可以对应多个Handler,Handler发消息到messageQueue,messageQueue中通过target字段分发消息到别的Handler

    MessageQueue在native初始化:从当前线程的缓存中拿到Looper,如果looper是null的话,先new一个looper,再将looper放到线程缓存中

    native层Looper的构造函数:创建eventfd,然后监听eventfd的读事件

    什么时候往eventfd中写东西呢?其他线程往当前线程的消息队列中插入新的消息,write函数就会往eventfd里写东西,当前线程如何监听eventfd的读事件?在pollOnce函数中,不停的循环调用pollInner来监听

    用awoken来消化读取事件

    问题2 主线程的Looper和子线程的Looper的区别

    1 应用进程启动后,主线程的Looper就已经准备好了,子线程的looper得prepare函数去创建

    2 子线程的looper可以退出的,主线程的looper不能退出,

    问题3 Looper和MessageQueue有什么关系

    1 java层Looper里包含一个MessageQueue,是一对一的关系

    2 native层的messageQueue中包含一个Looper,也是一对一的关系

    问题4 MessageQueue是怎么创建的

    java的MessageQueue对象创建的时候调用native的MessageQueue方法,然后会创建一个looper,looper里会创建一个eventfd,并且添加可读事件

    问题5 idleHandler

    线程空闲(messageQueue中消息为空或消息延时处理)时调用

    在queueIdle方法中可以处理一些事情,并返回一boolean值,返回true代表当线程idle(空闲)时,可以一直回调queueIdle这个方法,return false的话则只能收到一次这个queueIdle方法回调

    messageQueue里的addIdleHandler方法,就是往idleHandler的列表中加入这个idleHandler,

    当消息队列中没消息可处理时,则会将所有的idleHandlers转为数组,然后遍历这个数组,取出每个idleHandler,判断idleHandler的queueIdle方法为false,也就是idleHandler只要执行一次,就会将这个idleHandler移除,否则不移除,在下次循环中继续执行idleHandler中的任务

    如上图,首先往主线程中通过addIdleHandler添加了一个idleHandler, 然后这个idleHandler实现方法是创建类实现idleHandler接口,重写queueIdle方法,在方法中添加任务。

    IdleHandler的适用场景:

    使用场景:

    1 延时执行: 当界面启动时,需要处理很多逻辑,可能导致界面加载较慢,这时把一些不重要的逻辑延时执行,如上图所示,但上图并非很理想解决方案,此时就能适用IdleHandler

    2:批量任务:批量任务的特点是任务密集,且只关注最终结果,比如打开app,收到一大堆推送,然后刷新界面,如果来一条就刷新一次界面不太好,此时可以开个工作线程,来一个推送则封装成一个消息丢到工作线程中处理,当把所有的消息都处理完的时候,工作线程空闲下来,再去绘制结果刷新界面,这种场景就适合用IdleHandler去做

    问题6 主线程进入Loop循环,为什么没有ANR

    考点:

    1 ANR是什么

    上图是导致ANR的场景,概括就是应用在规定的时间内没有处理完指定的任务

    主线程中的loop无限循环不能退出,因为退出后应用就退出了,loop无限循环里不断从消息队列中取出消息然后分发消息,通过next()函数取出消息,当另一个线程往描述符写东西,nativePollOnce就会被唤醒,唤醒后再去检查消息队列有没有可处理的消息,有的话就把这个消息return

    当消息队列为空的时候主线程进入阻塞,其他线程发过来消息时,主线程又被激活

    总结:

    1 进入for死循环,依然可以处理AMS发过来的任务,AMS发过来的任务,都会封装成消息丢到消息队列去处理,

    2 没在规定的时间内完成一般指两点原因,主线程里有别的耗时任务,AMS发过来的任务就被delay了,或者AMS发过来的任务本身就很耗时,所以和loop的死循环无关

    问题7 ThreadLocal的原理,以及在Looper是如何应用的

    1 ThreadLocal的原理

    Looper就是保存在了threadLocal中,通过myLooper方法获得当前线程的threadLocal中保存的Looper,在不同的线程中,通过myLooper方法获得的Looper也就不同

    每个线程里都有一个Thread对象,Thread对象中有一张表,这个表其实是一个数组,存放了key和value,key就是指ThreadLocal的weakRefrence,value就是指ThreadLocal中存放的东西,一个应用中可以有多个ThreadLocal,每个ThreadLocal都有对应的Hash值,这个Hash值是根据hashCounter递增算出来的,然后用这个Hash值对数组的长度取余数,就能算出来ThreadLocal对应的key\value对在数组中所在的位置,如果发生hash冲突,则从当前的index开始往后遍历,看哪个是空的就存在哪里

    ThreadLocal原理总结:

    1 同一个ThreadLocal对象,在不同的线程get返回不同的value

    2 ThreadLoacl中有张表,数组的形式保存ThreadLoacl到value的映射关系

    3 这张表其实是数组形式,存放的key是ThreadLocal的weakReference,value是ThreadLocal中存放的东西,每个ThreadLocal都有对应的Hash值,这个hash值用hashCounter递增的方式算出,再用hash值对数组的长度取余数算出key/value对在数组中的位置

    4 hash冲突时,继续往数组后面遍历,直到找到空的位置存放

    问题8 Looper其他作用

    epoll_wait等可以处理的事件,然后遍历每个事件的fd,如果等于其他线程发来的mWakeEventFd,会向消息队列写消息让主线程进行处理,如果不等于的话,在else分支里,。。。。未完待续

    问题9 handler的消息延时怎么实现的

    消息队列其实是一个单链表,新消息到来时,按照消息触发时间的顺序来插入单链表的,如果消息队列是空的,或者新来的消息比消息队列的第一个时间还早的话,就插到第一个消息前面来作为新的消息的头节点,不然的话,按照消息的时间先后顺序插入到链表的对应位置当中,所以延时机制其实是指延时处理消息,而不是延时发送消息,发送消息会马上把消息插入到消息队列当中,只不过处理的时候是按照时间的先后顺序处理的,最下面的nativeWake函数,native层有一个native层的MessageQueue对象,然后会调用到native层的messageQueue的wake函数,然后线程收到eventFd事件就会被唤醒

    插入到消息队列后,如何保证一定按照预期的时间处理消息的呢,在loop()函数中,如果消息队列中没有要处理的消息next函数就会阻塞一直等待,直到有可用的消息,取到消息之后就可以调用dispatchMessage分发到消息对应的Handler,next函数有可用的消息才会返回,可用是指处理时间到了,如果当前的时间早于消息队列的第一个时间,epoll_wait就会在消息队列第一个时间减去当前时间得到的时间差后返回,不然当前时间大于消息队列的第一个时间,说明时间到了,就会把这个消息取出来返回,分发处理这个消息

    总结:1 消息队列按照消息触发时间先后顺序排列

               2 计算好消息的触发时间,当做epoll_wait的超时时间,超时时间到了线程就会被唤醒,去检查消息队列里有没有消息可以处理

               3 延时精度不高,消息可能处理比较耗时,导致后面的消息延时处理了 

    相关文章

      网友评论

          本文标题:FW-Handler

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