Looper.loop()是否导致主线程卡死问题探讨

知乎一个问题很好: 在执行ActivityThread的main函数体内,执行了Looper.loop()函数,这是个for(; ;)循环为何不会导致主线程进入死循环体从而被卡死呢?

首先理解什么叫做“线程进入死循环”, 在循环体内就是一段可执行的子程序,由于for(; ;)的调度导致这段子程序持续不断的在执行, 也就是持续的占用CPU资源, 从而导致当前线程的循环体外的子程序无法执行, 导致线程卡死的状态。

而实际上, 在Looper的loop循环体内是不会导致当前线程被卡死的,原因如下:
由于MessageQueue的阻塞机制, 主线程会处于阻塞状态, 保证了程序的不退出, 所以可以看作是一种“假卡死”状态, 倘若这个循环体结束了意味着主线程该停止运行了, 那么app可以退出了。

  • MessageQueue的阻塞机制: 在循环体内第一件事儿就是从mq里面取出一个msg操作, 即queue.next(); 此操作为阻塞操作, 如果当前线程阻塞的话就会释放掉CPU的占用, 进入阻塞状态.

而在这个循环体内是如何调用到循环体外部的子程序呢?

  • 通过从messageQueue取出来的msg的targetHandler机制, 把取出来的消息dispatch到对应的handler那里, 在handler的handleMessage函数里面去执行一些逻辑, 诸如onCreate,onResume之类的函数. 这样就可以在循环体内执行循环体外的子程序了。

ActivityThread内的所有message就是来自其他线程send过来的,全部都放到了这个MessageQueue对象中; 例如binder线程的消息也是通过handler方式传递给ActivityThread的queuede。
而activity的生命周期调度也是靠ActivityThread的H(extends Handler)类, 任何一个与生命周期相关的消息, 都会把target设置为H, 这样才能够确保在for(; ;)中取出的每一个message都能够通过message.target.sendMessage(msg)的方式通知H类的handleMessage()方法,进而调用不同的生命周期处理函数。

让ActivityThread进入”假卡死”状态, 一来不需要持续的占用CPU资源, 二来可以保证应用的不退出, 随时可以相应消息avaliable, 而我们的手机大多情况下都是处于等待用户输入的状态, ActivityThread的假卡死状态是最适合这种模式的交互方式的设备。