参考:
https://www.zhihu.com/question/34652589 // Handler
https://blog.csdn.net/rock_joker/article/details/76735333 // Linux pipe/epoll
https://www.cnblogs.com/coder2012/archive/2013/07/22/3204730.html 进程状态
1,从Handler到Looper
以上就是Handler机制的概要,每个部分都扮演着自己的角色
* Handler:发送消息和最后接收并处理消息
* Message:消息对象
* MessageQueue:消息队列(未被CPU处理的消息,都放这了)
* Looper:不断地循环MessageQueue,若有消息则执行,若无消息则阻塞
2,Looper一直循环,为什么不会死循环卡死,即:没有高频率占用CPU
1) Looper的调用
#ActivityThread.java::main()
public static void main(String[] args) {
...
Looper.prepareMainLooper();
// 创建ActivityThread
ActivityThread thread = new ActivityThread();
thread.attach(false);
...
Looper.loop(); // 消息循环
throw new RuntimeException("Main thread loop unexpectedly exited");
}
可以看出,Looper.loop()之后,就抛出异常,所以按照现象,loop()中应该是一个永真循环(死循环,永不退出)
2) loop()循环的实现
#Looper.java::loop()
public static void loop() {
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
msg.target.dispatchMessage(msg); // 分发消息,等待实现处理
msg.recycleUnchecked();
}
}
#MessageQueue.java::next()
Message next() {
...
for (;;) {
nativePollOnce(ptr, nextPollTimeoutMillis); // 轮询到下一个消息
synchronized (this) {
... // 遍历下一个消息,若无消息,则继续;若有消息则返回Msg
}
...
}
}
#android_os_MessageQueue.cpp::android_os_MessageQueue_nativePollOnce()
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, jlong ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast(ptr);
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
#android_os_MessageQueue.cpp::pollOnce()
void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
...
mLooper->pollOnce(timeoutMillis);
...
}
#Looper.cpp::pollOnce()
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
... // 中间有 return result;
result = pollInner(timeoutMillis);
}
}
#Looper.cpp::pollInner()
int Looper::pollInner(int timeoutMillis) {
...
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis); // Poll.
mLock.lock(); // Acquire lock.
if (mEpollRebuildRequired) {
mEpollRebuildRequired = false;
rebuildEpollLocked();
}
... // Handle all events and message
mLock.unlock(); // Release lock.
... // Invoke all response callbacks.
return result;
}
#Looper.cpp::rebuildEpollLocked
void Looper::rebuildEpollLocked() {
...
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
...
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
for (size_t i = 0; i < mRequests.size(); i++) {
...
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem);
}
}
* loop()中是一个永真循环,而每次调用next() 最终调用到pollInner(),执行 epoll_wait语句
* epoll_wait、epolll_create、epoll_ctl涉及到Linux的pipe/epoll机制。大致功能是,当前线程会释放CPU资源进入休眠状态,直到有消息或事务发生,通过往pipe管道写端写入数据唤醒工作(epoll_wait得到执行)。即:epoll是阻塞的
==> 结论:Looper中执行一个永真循环,其中每次有消息则执行,无消息时,则阻塞。因此不会消耗大量CPU资源
3,拓展(while循环和占用CPU案例、进程状态和CPU调用关联)
1)while循环和占用CPU案例
#SampleA
while (true) {
index++;
if (index > 1024) {
index = 0;
}
}
#SampleB
while (true) {
Thread.sleep(1);
index++;
if (index > 1024) {
index = 0;
}
}
* SampleA会导致CPU占有率居高不下,SampleB对CPU占有率影响基本可以忽略不计
* 原因:CPU执行频率以纳秒为单位而,而每次sleep 1秒,相当于阻塞当前线程,放弃占用CPU资源。从而对CPU占用率就变得极小
2)进程状态和CPU调用关联
进程状态 | CPU情况 |
运行 | 该进程正在被CPU执行 |
就绪 | 进程资源准备好了,进入队列排队,等待CPU执行;CPU在执行其它任务 |
阻塞 | 进程未准备好,需要等待信号,进入队列排队;CPU在执行其它任务 |
总结一下:进程可以被执行时,CPU依照调度可以执行该任务(不一定执行);进程阻塞时,让出CPU