天天看點

handle機制:Loop死循環為何不會導緻應用卡死,主線程死循環為何不會消耗CPU資源

  • Looper.loop();裡面維護了一個死循環方法,對于線程是一段可執行的代碼,當可執行代碼執行完成後,線程生命周期便該終止了,線程退出。而對于主線程,我們是絕不希望會被運作一段時間,自己就退出,那麼如何保證能一直存活呢?簡單做法就是可執行代碼是能一直執行下去的,死循環便能保證不會被退出,這就是主線程需要死循環的原因。例如,binder線程也是采用死循環的方法,通過循環方式不同與Binder驅動進行讀寫操作,當然并非簡單地死循環,無消息時會休眠。死循環處理其他事務通過建立新線程的方式。真正會卡死主線程的操作是在回調方法onCreate/onStart/onResume等操作時間過長,會導緻掉幀,甚至發生ANR,looper.loop本身不會導緻應用卡死。
  • 關于主線程的死循環一直運作是不是特别消耗CPU資源的問題 Linux 中有pipe/epoll機制,簡單說就是在主線程的MessageQueue沒有消息時,便阻塞在loop的queue.next()中的nativePollOnce()方法裡,此時主線程會釋放CPU資源進入休眠狀态,直到下個消息到達或者有事務發生,通過往pipe管道寫端寫入資料來喚醒主線程工作。這裡采用的epoll機制,是一種IO多路複用機制,可以同時監控多個描述符,當某個描述符就緒(讀或寫就緒),則立刻通知相應程式進行讀或寫操作,本質同步I/O,即讀寫是阻塞的。 是以說,主線程大多數時候都是處于休眠狀态,并不會消耗大量CPU資源。
  • 線程預設沒有Looper的,如果需要使用Handler就必須為線程建立Looper。我們經常提到的主線程,也叫UI線程,它就是ActivityThread,ActivityThread被建立時就會初始化Looper,這也是在主線程中預設可以使用Handler的原因。
  • 「Activity 啟動過程」

    比如收到msg=H.LAUNCH_ACTIVITY,則調用ActivityThread.handleLaunchActivity()方法,最終會通過反射機制,建立Activity執行個體,然後再執行Activity.onCreate()等方法;

  • 收到msg=H.PAUSE_ACTIVITY,則調用ActivityThread.handlePauseActivity()方法,最終會執行Activity.onPause()等方法
  • 主線程的消息是App程序中的其他線程通過Handler發送給主線程
  • system_server程序 系統程序,java framework架構的核心載體,裡面運作了大量的系統服務,比如這裡提供ApplicationThreadProxy(簡稱ATP),ActivityManagerService(簡稱AMS),這個兩個服務都運作在system_server程序的不同線程中,由于ATP和AMS都是基于IBinder接口,都是binder線程,binder線程的建立與銷毀都是由binder驅動來決定的。
  • App程序 應用程式,主線程主要負責Activity/Service等元件的生命周期以及UI相關操作都運作在這個線程; 另外,每個App程序中至少會有兩個binder線程 ApplicationThread(簡稱AT)和ActivityManagerProxy(簡稱AMP)
  • Binder用于不同程序之間通信,由一個程序的Binder用戶端向另一個程序的服務端發送事務,而handler用于同一個程序中不同線程的通信,
  • 主線程的消息循環模型
  • 進入死循環之前便建立了新binder線程,在ActivityThread的main方法中
ActivityThread thread = new ActivityThread();
        thread.attach(false);
           
  • 而上述的attach方法:
final ApplicationThread mAppThread = new ApplicationThread();
           
private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
         
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            
        }
    }
           
  • ActivityThread通過ApplicationThread和AMS進行程序間通訊,AMS以程序間通信的方式完成ActivityThread的請求後會回調ApplicationThread中的Binder方法,然後ApplicationThread會向H發送消息,H收到消息後會将ApplicationThread中的邏輯切換到ActivityThread中去執行,即切換到主線程中去執行,