无码人妻精一区二区三区,eeuss影院www在线观看,无码精品久久久久久人妻中字,日韩av高清在线看片

推薦新聞
Android中為什么主線程不會(huì)因?yàn)長ooper.loop()里的死循環(huán)卡死?
發(fā)布者:深藍(lán)互聯(lián)
發(fā)布時(shí)間:2019-07-22
點(diǎn)擊:次

1.Android中為什么主線程不會(huì)因?yàn)長ooper.loop()里的死循環(huán)卡死?

2.沒看見哪里有相關(guān)代碼為這個(gè)死循環(huán)準(zhǔn)備了一個(gè)新線程去運(yùn)轉(zhuǎn)?

3.Activity的生命周期這些方法這些都是在主線程里執(zhí)行的吧,那這些生命周期方法是怎么實(shí)現(xiàn)在死循環(huán)體外能夠執(zhí)行起來的?

--------------------------------------------------------------------------------------------------------------------------------------

(1) Android中為什么主線程不會(huì)因?yàn)長ooper.loop()里的死循環(huán)卡死?

這里涉及線程,先說說說進(jìn)程/線程,進(jìn)程:每個(gè)app運(yùn)行時(shí)前首先創(chuàng)建一個(gè)進(jìn)程,該進(jìn)程是由Zygote fork出來的,用于承載App上運(yùn)行的各種Activity/Service等組件。進(jìn)程對(duì)于上層應(yīng)用來說是完全透明的,這也是google有意為之,讓App程序都是運(yùn)行在Android Runtime。大多數(shù)情況一個(gè)App就運(yùn)行在一個(gè)進(jìn)程中,除非在AndroidManifest.xml中配置Android:process屬性,或通過native代碼fork進(jìn)程。

線程:線程對(duì)應(yīng)用來說非常常見,比如每次new Thread().start都會(huì)創(chuàng)建一個(gè)新的線程。該線程與App所在進(jìn)程之間資源共享,從Linux角度來說進(jìn)程與線程除了是否共享資源外,并沒有本質(zhì)的區(qū)別,都是一個(gè)task_struct結(jié)構(gòu)體,在CPU看來進(jìn)程或線程無非就是一段可執(zhí)行的代碼,CPU采用CFS調(diào)度算法,保證每個(gè)task都盡可能公平的享有CPU時(shí)間片。

有了這么準(zhǔn)備,再說說死循環(huán)問題:

對(duì)于線程既然是一段可執(zhí)行的代碼,當(dāng)可執(zhí)行代碼執(zhí)行完成后,線程生命周期便該終止了,線程退出。而對(duì)于主線程,我們是絕不希望會(huì)被運(yùn)行一段時(shí)間,自己就退出,那么如何保證能一直存活呢?簡單做法就是可執(zhí)行代碼是能一直執(zhí)行下去的,死循環(huán)便能保證不會(huì)被退出,例如,binder線程也是采用死循環(huán)的方法,通過循環(huán)方式不同與Binder驅(qū)動(dòng)進(jìn)行讀寫操作,當(dāng)然并非簡單地死循環(huán),無消息時(shí)會(huì)休眠。但這里可能又引發(fā)了另一個(gè)問題,既然是死循環(huán)又如何去處理其他事務(wù)呢?通過創(chuàng)建新線程的方式。

真正會(huì)卡死主線程的操作是在回調(diào)方法onCreate/onStart/onResume等操作時(shí)間過長,會(huì)導(dǎo)致掉幀,甚至發(fā)生ANR,looper.loop本身不會(huì)導(dǎo)致應(yīng)用卡死。

 

(2) 沒看見哪里有相關(guān)代碼為這個(gè)死循環(huán)準(zhǔn)備了一個(gè)新線程去運(yùn)轉(zhuǎn)?

事實(shí)上,會(huì)在進(jìn)入死循環(huán)之前便創(chuàng)建了新binder線程,在代碼ActivityThread.main()中:
public static void main(String[] args) {
        ....

        //創(chuàng)建Looper和MessageQueue對(duì)象,用于處理主線程的消息
        Looper.prepareMainLooper();

        //創(chuàng)建ActivityThread對(duì)象
        ActivityThread thread = new ActivityThread(); 

        //建立Binder通道 (創(chuàng)建新線程)
        thread.attach(false);

        Looper.loop(); //消息循環(huán)運(yùn)行
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

thread.attach(false);便會(huì)創(chuàng)建一個(gè)Binder線程(具體是指ApplicationThread,Binder的服務(wù)端,用于接收系統(tǒng)服務(wù)AMS發(fā)送來的事件),該Binder線程通過Handler將Message發(fā)送給主線程

另外,ActivityThread實(shí)際上并非線程,不像HandlerThread類,ActivityThread并沒有真正繼承Thread類,只是往往運(yùn)行在主線程,該人以線程的感覺,其實(shí)承載ActivityThread的主線程就是由Zygote fork而創(chuàng)建的進(jìn)程。

主線程的死循環(huán)一直運(yùn)行是不是特別消耗CPU資源呢? 其實(shí)不然,這里就涉及到Linux pipe/epoll機(jī)制,簡單說就是在主線程的MessageQueue沒有消息時(shí),便阻塞在loop的queue.next()中的nativePollOnce()方法里,詳情見Android消息機(jī)制1-Handler(Java層),此時(shí)主線程會(huì)釋放CPU資源進(jìn)入休眠狀態(tài),直到下個(gè)消息到達(dá)或者有事務(wù)發(fā)生,通過往pipe管道寫端寫入數(shù)據(jù)來喚醒主線程工作。這里采用的epoll機(jī)制,是一種IO多路復(fù)用機(jī)制,可以同時(shí)監(jiān)控多個(gè)描述符,當(dāng)某個(gè)描述符就緒(讀或?qū)懢途w),則立刻通知相應(yīng)程序進(jìn)行讀或?qū)懖僮?,本質(zhì)同步I/O,即讀寫是阻塞的。 所以說,主線程大多數(shù)時(shí)候都是處于休眠狀態(tài),并不會(huì)消耗大量CPU資源。

 

(3) Activity的生命周期是怎么實(shí)現(xiàn)在死循環(huán)體外能夠執(zhí)行起來的?

ActivityThread的內(nèi)部類H繼承于Handler,通過handler消息機(jī)制,簡單說Handler機(jī)制用于同一個(gè)進(jìn)程的線程間通信。

Activity的生命周期都是依靠主線程的Looper.loop,當(dāng)收到不同Message時(shí)則采用相應(yīng)措施:
在H.handleMessage(msg)方法中,根據(jù)接收到不同的msg,執(zhí)行相應(yīng)的生命周期。

比如收到msg=H.LAUNCH_ACTIVITY,則調(diào)用ActivityThread.handleLaunchActivity()方法,最終會(huì)通過反射機(jī)制,創(chuàng)建Activity實(shí)例,然后再執(zhí)行Activity.onCreate()等方法;
再比如收到msg=H.PAUSE_ACTIVITY,則調(diào)用ActivityThread.handlePauseActivity()方法,最終會(huì)執(zhí)行Activity.onPause()等方法。 上述過程,我只挑核心邏輯講,真正該過程遠(yuǎn)比這復(fù)雜。

主線程的消息又是哪來的呢?當(dāng)然是App進(jìn)程中的其他線程通過Handler發(fā)送給主線程,請(qǐng)看接下來的內(nèi)容:

 

--------------------------------------------------------------------------------------------------------------------------------------
最后,從進(jìn)程與線程間通信的角度,通過一張圖加深大家對(duì)App運(yùn)行過程的理解:


system_server進(jìn)程是系統(tǒng)進(jìn)程,java framework框架的核心載體,里面運(yùn)行了大量的系統(tǒng)服務(wù),比如這里提供ApplicationThreadProxy(簡稱ATP),ActivityManagerService(簡稱AMS),這個(gè)兩個(gè)服務(wù)都運(yùn)行在system_server進(jìn)程的不同線程中,由于ATP和AMS都是基于IBinder接口,都是binder線程,binder線程的創(chuàng)建與銷毀都是由binder驅(qū)動(dòng)來決定的。

 

App進(jìn)程則是我們常說的應(yīng)用程序,主線程主要負(fù)責(zé)Activity/Service等組件的生命周期以及UI相關(guān)操作都運(yùn)行在這個(gè)線程; 另外,每個(gè)App進(jìn)程中至少會(huì)有兩個(gè)binder線程 ApplicationThread(簡稱AT)和ActivityManagerProxy(簡稱AMP),除了圖中畫的線程,其中還有很多線程,比如signal catcher線程等,這里就不一一列舉。

Binder用于不同進(jìn)程之間通信,由一個(gè)進(jìn)程的Binder客戶端向另一個(gè)進(jìn)程的服務(wù)端發(fā)送事務(wù),比如圖中線程2向線程4發(fā)送事務(wù);而handler用于同一個(gè)進(jìn)程中不同線程的通信,比如圖中線程4向主線程發(fā)送消息。

結(jié)合圖說說Activity生命周期,比如暫停Activity,流程如下:
  1. 線程1的AMS中調(diào)用線程2的ATP;(由于同一個(gè)進(jìn)程的線程間資源共享,可以相互直接調(diào)用,但需要注意多線程并發(fā)問題)
  2. 線程2通過binder傳輸?shù)紸pp進(jìn)程的線程4;
  3. 線程4通過handler消息機(jī)制,將暫停Activity的消息發(fā)送給主線程;
  4. 主線程在looper.loop()中循環(huán)遍歷消息,當(dāng)收到暫停Activity的消息時(shí),便將消息分發(fā)給ActivityThread.H.handleMessage()方法,再經(jīng)過方法的調(diào)用,最后便會(huì)調(diào)用到Activity.onPause(),當(dāng)onPause()處理完后,繼續(xù)循環(huán)loop下去。

 

關(guān)注深藍(lán)互聯(lián)公眾號(hào)
Copyright ? 2013-2025 深藍(lán)互聯(lián) 版權(quán)所有
友情鏈接: