相关名词
mq:消息队列MessageQuene的缩写
流程
java的mq初始化的时候会先初始化native的mq再native的mq中又创建了native层的looper。同时native层把自己mq传入到了java中mq的mptr对象
java消息队列中调用nativepollonce(javaMq中的next方法)最终会调用到mtpr的nativepollonce(mtpr是native层的消息队列对象)该方法用于等待一个java层的消息来临
native的mq的nativepollonce会调用looper的pollonce方法(这个looper是native层的)
pollonce方法中会取出responce(其他监听的fd来的request封装的)处理。
接着会调用pollinner。 pollinner才是真正决定是否有消息处理的地方。 pollinner中会等待pipe唤醒(代表有消息来了需要处理),唤醒之后查看是否是消息来还是其他fd发出的request。
之后
取出管道的事件进行处理,先处理native的消息。
fd发出的request:对其封装成一个response。添加到mresponse数组中。 等待native消息处理完后再取出response数组处理监听fd得到的事件。
最后返回java的消息回到java的nativepollonce方法中。
java和native中都是利用handler发消息,都是调用的管道流进行唤醒。
java层的next会调用nativepollonce进入到native的消息队列中,native层looper的pollinner实现阻塞。(唤醒可能是由于消息或者fd发生request)。
为fd的request创建对应response添加到response数组中,等待native的消息处理完,在处理request,接着返回到java的消息。java的mq恢复处理。
注意点
根据上面的分析流程我们可以知道,即使CPU充足堆栈情况正常也不能一定保证java发出的消息可以按计划得到执行。这个时候很有可能是native在处理自己的消息或者在native中对监听到的fd做处理,最后才会轮到java中的消息处理。nativePollonce才因此返回进入java消息处理过程。
mq为什么采用epoll机制?
select和epoll机制区别:
1.关于监听fd的复制次数
select每次调用都需要将监听的事件复制到内核中。而epoll只需要在epllctl进行加入操作时才复制一份
2.效率问题
epoll使用红黑树保存监听事件,而select内部使用数组存储(监听事件数量有限10个)。当监听事件变得多时select效率没有epoll好,但是当事件少时两者查找效率差不多
epoll和pipe区别
epoll等待监听事件触发。等待监听的fd和对应接受的动作
使用pipe用于唤醒,使用pipe用作线程间通信的原因是因为:写端发送的数据读端不感兴趣,只做简单的唤醒,无需对数据处理,因此使用pipe读端不关心数据只起到唤醒作用