消息队列排队过程中的消息。这第一条消息将首先被处理。但假设消息本身指定要处理的时间。我们必须等待,直到时间的消息处理能力。新闻MessageQueue正在使用Message类的表示,队列中的邮件保存结构清单,Message内部对象包括:next变量,此变量指向下一个消息对象。

MessageQueue中的两个主要函数是“取出消息”和“加入消息”,各自是next()和enquenceMessage()。

next()函数

final Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0; for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(mPtr, nextPollTimeoutMillis); synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
final Message msg = mMessages;
if (msg != null) {
final long when = msg.when;
if (now >= when) {
mBlocked = false;
mMessages = msg.next;
msg.next = null;
if (Config.LOGV) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
} else {
nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);
}
} else {
nextPollTimeoutMillis = -1;
} // If first time, then get the number of idlers to run.
if (pendingIdleHandlerCount < 0) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount == 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
} if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
} // Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
} if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
} // Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}

该函数的内部流程分三步:

1. 调用nativePollOnce(mPtr, int time)。这是一个JNI函数,作用是从消息队列中取出一个消息。

MessageQueue类内部本身并没有保存消息队列,真正的消息队列数据保存在JNI中的C代码中,在C环境中创建了一个NativeMessageQueue数据对象。这就是nativePollOnce()第一个參数的意义。它是一个int型变量,在C环境中。该变量被强制转换为一个NativeMessageQueue对象。在C环境中。假设消息队列中没有消息,将导致当前线程被挂起(wait),假设消息队列中有消息,则C代码中将把该消息赋值给Java环境中的mMessages变量。

2. 接下来的代码被包括在synchronized(this)中,this被用作取消息和写消息的锁。不过推断消息所指定的运行时间是否到了。

假设到了。就返回该消息。并将mMessages变量置空。假设时间还没有到,则尝试读取下一个消息。

3. 假设mMessages为空,则说明C环境中的消息队列没有可运行的消息了,因此,运行mPendingIdleHanlder列表中的“空暇回调函数”。

能够向MessageQueue中注冊一些“空暇回调函数”。从而当线程中没有消息可处理的时候去运行这些“空暇代码”。

enquenceMessage()函数

final boolean enqueueMessage(Message msg, long when) {
if (msg.when != 0) {
throw new AndroidRuntimeException(msg
+ " This message is already in use.");
}
if (msg.target == null && !mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit");
}
final boolean needWake;
synchronized (this) {
if (mQuiting) {
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
} else if (msg.target == null) {
mQuiting = true;
} msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked; // new head, might need to wake up
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
needWake = false; // still waiting on head, no need to wake up
}
}
if (needWake) {
nativeWake(mPtr);
}
return true;
}

该函数内部分为两步:

1. 将參数msg赋值给mMessages。

2. 调用nativeWake(mPtr)。这是一个JNI函数,其内部会将mMessages消息加入到C环境中的消息队列中,并假设该消息线程正在等待(wait)状态,然后唤醒线程。

版权声明:本文博客原创文章,博客,未经同意,不得转载。

【核心研究】消息队列_MessageQueue的更多相关文章

  1. MQ选型对比ActiveMQ,RabbitMQ,RocketMQ,Kafka 消息队列框架选哪个?

    最近研究消息队列,发现好几个框架,搜罗一下进行对比,说一下选型说明: 1)中小型软件公司,建议选RabbitMQ.一方面,erlang语言天生具备高并发的特性,而且他的管理界面用起来十分方便.不考虑r ...

  2. MSMQ消息队列的安装、启用

    最近研究消息队列,先从微软自带的MSMQ开始,百度如何安装,方式如下: 控制面板---程序和功能--启用和关闭windows功能--Microsoft Message Queue(MSMQ)服务器 默 ...

  3. 高性能消息队列 CKafka 核心原理介绍(上)

    欢迎大家前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~ 作者:闫燕飞 1.背景 Ckafka是基础架构部开发的高性能.高可用消息中间件,其主要用于消息传输.网站活动追踪.运营监控.日志聚合.流式 ...

  4. 【iCore4 双核心板_uC/OS-II】例程九:消息队列

    一.实验说明: 前面介绍通过信息传递可以进行任务间的交流,信息也可以直接发送给一个任务,在uC/OS-II中每一个任务在它们内部都有一个消息队列,也即任务消息队列,用户可以直接给一个任务发送消息,不需 ...

  5. 高并发架构系列:MQ消息队列的12点核心原理总结

    消息队列已经逐渐成为分布式应用场景.内部通信.以及秒杀等高并发业务场景的核心手段,它具有低耦合.可靠投递.广播.流量控制.最终一致性 等一系列功能. 无论是 RabbitMQ.RocketMQ.Act ...

  6. RocketMQ读书笔记5——消息队列的核心机制

    [Broker简述] Broker是RocketMQ的核心,大部分“重量级”的工作都是由Broker完成的,包括: 1.接受Producer发过来的消息: 2.处理Consumer的消费信息请求: 3 ...

  7. 消息队列MQ核心原理全面总结(11大必会原理)

    消息队列已经逐渐成为分布式应用场景.内部通信.以及秒杀等高并发业务场景的核心手段,它具有低耦合.可靠投递.广播.流量控制.最终一致性 等一系列功能. 无论是 RabbitMQ.RocketMQ.Act ...

  8. MQ消息队列的12点核心原理总结

    1. 消息生产者.消息者.队列 消息生产者Producer:发送消息到消息队列. 消息消费者Consumer:从消息队列接收消息. Broker:概念来自与Apache ActiveMQ,指MQ的服务 ...

  9. NoSQL初探之人人都爱Redis:(3)使用Redis作为消息队列服务场景应用案例

    一.消息队列场景简介 “消息”是在两台计算机间传送的数据单位.消息可以非常简单,例如只包含文本字符串:也可以更复杂,可能包含嵌入对象.消息被发送到队列中,“消息队列”是在消息的传输过程中保存消息的容器 ...

随机推荐

  1. LoadImage()使用

    该系统被定义: WINUSERAPIHANDLEWINAPILoadImageA(    HINSTANCE,    LPCSTR,    UINT,    int,    int,    UINT) ...

  2. hive的非交互模式

    在linux的终端运行:$HIVE_HOME/bin/hive 会进入交互模式: $HIVE_HOME/bin/hive  -e或者-f 是非交互模式 1.非交互模式运行HQL语句 $HIVE_HOM ...

  3. POJ 1905-Expanding Rods(二分法+计算几何)

    题目地址:POJ 1905 题意:一根某种材料做的直杆被夹在两面墙之间,当他受热时长度变长,就会因两面墙的挤压而向上隆起.长度变化函数为 L'=(1+n*C)*L,给定L,C,n,求向上拱起的高度H. ...

  4. Lua相关的知识

    http://stackoverflow.com/questions/5438751/how-to-debug-lua-remotely http://cn.bing.com/search?q=org ...

  5. mysql 插入Emoji表情报错

    今天做的了个获取微信粉丝的功能,发现将昵称插入数据库报错.长度肯定是够的 Incorrect string value: '\xF0\x9F\x98\x84\xF0\x9F 找了点资料发现UTF-8编 ...

  6. MyEclipse每次修改js有另一种部署

    今天在做时间格式显示这块内容的时候.我改动了这个js函数,同一时候凝视的掉了其它的一些替换的方法,可是在浏览器中执行发现效果一点也没有改变.于是debug js,发现浏览器中识别的还是之前未改动的js ...

  7. 2.大约QT数据库操作,简单的数据库连接操作,增删改查数据库,QSqlTableModel和QTableView,事务性操作,大约QItemDelegate 代理

     Linux下的qt安装,命令时:sudoapt-get install qt-sdk 安装mysql数据库,安装方法參考博客:http://blog.csdn.net/tototuzuoquan ...

  8. ThinkPad E530 Fedora 20 无线上网问题

    它一直在使用 Fedora 家庭 Linux. 但它自带的无线网卡驱动似下一些问题,通常,有时连接,有时你不能. 经常搜索不到的家用无线路由器. 因为家里有网线所以一直没有在意.没什么事就折腾了一下. ...

  9. STL之容器适配器queue的实现框架

    说明:本文仅供学习交流,转载请标明出处,欢迎转载! 上篇文章STL之容器适配器stack的实现框架已经介绍了STL是怎样借助基础容器实现一种经常使用的数据结构stack (栈),本文介绍下第二种STL ...

  10. Cocos2d-x 3.x plist+png 做动画

    ***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...