<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] # Java層 一個線程綁定一個Looper,一個Looper維護一個MessageQueue隊列,而一個線程可以對應多個Handler。 ## ActivityThread ~~~ public static void main(String[] args) { ... Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } ... } ~~~ 核心是Looper.prepareMainLooper() ## Looper ### Looper.prepareMainLooper()/Looper.prepare() ~~~ public static void prepareMainLooper() { prepare(false);//核心 synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); ~~~ ### Looper.loop() ~~~ public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; ... for (;;) { Message msg = queue.next(); // 可能會堵塞 if (msg == null) { // 結束 return; } // This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } ... try { //處理 msg.target就是 handle msg.target.dispatchMessage(msg); } finally { } ... . if (logging != null) { logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); } ... msg.recycleUnchecked(); } ~~~ 1. 構建一個死循環 2. 從MessageQueue取出msg 3. 交給handled.dispatchMessag ## MessageQueue MessageQueue中最重要的就是兩個方法: 1.enqueueMessage向隊列中插入消息 2.next 從隊列中取出消息 MessageQueue的底層數據結構是單向鏈表,MessageQueue中的成員變量mMessages指向的就是該鏈表的頭部元素。 ### enqueueMessage 先分析enqueueMessage: ~~~ boolean enqueueMessage(Message msg, long when) { if (msg.target == null) {//msg.target就是發送此消息的Handler throw new IllegalArgumentException("Message must have a target."); } if (msg.isInUse()) {//表示此消息正在被使用 throw new IllegalStateException(msg + " This message is already in use."); } synchronized (this) { if (mQuitting) {//表示此消息隊列已經被放棄了 IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); msg.when = when;//將延遲時間封裝到msg內部 Message p = mMessages;//消息隊列的第一個元素 boolean needWake; if (p == null || when == 0 || when < p.when) { //如果此隊列中頭部元素是null(空的隊列,一般是第一次),或者此消息不是延時的消息,則此消息需要被立即處理,此時會將這個消息作為新的頭部元素,并將此消息的next指向舊的頭部元素,然后判斷如果Looper獲取消息的線程如果是阻塞狀態則喚醒它,讓它立刻去拿消息處理 msg.next = p; mMessages = msg; needWake = mBlocked; } else { //如果此消息是延時的消息,則將其添加到隊列中,原理就是鏈表的添加新元素,按照when,也就是延遲的時間來插入的,延遲的時間越長,越靠后,這樣就得到一條有序的延時消息鏈表,取出消息的時候,延遲時間越小的,就被先獲取了。插入延時消息不需要喚醒Looper線程。 needWake = mBlocked && p.target == null && msg.isAsynchronous(); Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) {//喚醒線程 nativeWake(mPtr); } } return true; } ~~~ 源碼中主要的地方我給了注釋,可以參考參考。 由此可以看出: MessageQueue中enqueueMessage方法的目的有兩個: 1.插入消息到消息隊列 2.喚醒Looper中等待的線程(如果是及時消息并且線程是阻塞狀態) 同時我們知道了MessageQueue的底層數據結構是單向鏈表,MessageQueue中的成員變量mMessages指向的就是該鏈表的頭部元素 ### next ~~~java Message next() { final long ptr = mPtr; if (ptr == 0) { //從注釋可以看出,只有looper被放棄的時候(調用了quit方法)才返回null,mPtr是MessageQueue的一個long型成員變量,關聯的是一個在C++層的MessageQueue,阻塞操作就是通過底層的這個MessageQueue來操作的;當隊列被放棄的時候其變為0。 return null; } int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } //阻塞方法,主要是通過native層的epoll監聽文件描述符的寫入事件來實現的。 //如果nextPollTimeoutMillis=-1,一直阻塞不會超時。 //如果nextPollTimeoutMillis=0,不會阻塞,立即返回。 //如果nextPollTimeoutMillis>0,最長阻塞nextPollTimeoutMillis毫秒(超時),如果期間有程序喚醒會立即返回。 nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) { //msg.target == null表示此消息為消息屏障(通過postSyncBarrier方法發送來的) //如果發現了一個消息屏障,會循環找出第一個異步消息(如果有異步消息的話),所有同步消息都將忽略(平常發送的一般都是同步消息) do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { // 如果消息此刻還沒有到時間,設置一下阻塞時間nextPollTimeoutMillis,進入下次循環的時候會調用nativePollOnce(ptr, nextPollTimeoutMillis)進行阻塞; nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { //正常取出消息 //設置mBlocked = false代表目前沒有阻塞 mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; msg.markInUse(); return msg; } } else { //沒有消息,會一直阻塞,直到被喚醒 nextPollTimeoutMillis = -1; } if (mQuitting) { dispose(); return null; } pendingIdleHandlerCount = 0; nextPollTimeoutMillis = 0; } } ~~~ 由此可以看出: 1.當首次進入或所有消息隊列已經處理完成,由于此刻隊列中沒有消息(mMessages為null),這時nextPollTimeoutMillis = -1 ,然后會處理一些不緊急的任務(IdleHandler),之后線程會一直阻塞,直到被主動喚醒(插入消息后根據消息類型決定是否需要喚醒)。 2.讀取列表中的消息,如果發現消息屏障,則跳過后面的同步消息。 3.如果拿到的消息還沒有到時間,則重新賦值nextPollTimeoutMillis = 延時的時間,線程會阻塞,直到時間到后自動喚醒 4.如果消息是及時消息或延時消息的時間到了,則會返回此消息給looper處理。 通過enqueueMessage和next兩個方法的分析我們不難得出: 消息的入列和出列是一個生產-消費者模式,Looper.loop()在一個線程中調用next()不斷的取出消息,另外一個線程則通過enqueueMessage向隊列中插入消息,所以在這兩個方法中使用了synchronized (this) {}同步機制,其中this為MessageQueue對象,不管在哪個線程,這個對象都是同一個,因為Handler中的mQueue指向的是Looper中的mQueue,這樣防止了多個線程對同一個隊列的同時操作。 ### Handler.sendMessageDelayed()怎么實現延遲的? 前面我們分析了如果拿到的消息還沒有到時間,則會重新設置超時時間并賦值給nextPollTimeoutMillis,然后調用nativePollOnce(ptr, nextPollTimeoutMillis)進行阻塞,這是一個本地方法,會調用底層C++代碼,C++代碼最終會通過Linux的epoll監聽文件描述符的寫入事件來實現延遲的。 ### 為什么這個死循環不會造成ANR異常呢? 我們知道Android 的是由事件驅動的,looper.loop() 不斷地接收事件、處理事件,每一個點擊觸摸或者說Activity的生命周期都是運行在 Looper的控制之下,如果它停止了,應用也就停止了。只能是某一個消息或者說對消息的處理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它,這也就是我們為什么不能在UI線程中處理耗時操作的原因。 主線程Looper從消息隊列讀取消息,當讀完所有消息時,主線程阻塞。子線程往消息隊列發送消息,喚醒主線程,主線程被喚醒只是為了讀取消息,當消息讀取完畢,再次睡眠。因此loop的循環并不會對CPU性能有過多的消耗。 ### Handle #### dispatchMessage ### Message ## Native層 在linux新的內核中使用了epoll來替換它,相比于select,epoll最大的好處在于它不會隨著監聽文件描述符數目的增長而效率降低,select機制是采用輪詢來處理的,輪詢的fd數目越多,效率也就越低。epoll的接口非常簡單就只有三個函數: int epoll_create(int size);創建一個epoll句柄,當這個句柄創建完成之后,在/proc/進程id/fd中可以看到這個fd。 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);注冊事件函數。 int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);等待事件的發生,參數timeout是超時時間毫秒值,0會立即返回,-1將不確定,也就是說有可能永久阻塞。該函數返回需要處理的事件數目,如返回0表示已超時。 ## ThreadLocal ## 參考資料 [從源碼角度分析java層Handler機制](https://blog.csdn.net/andywuchuanlong/article/details/48160127) [從源碼角度分析native層消息機制與java層消息機制的關聯](https://blog.csdn.net/andywuchuanlong/article/details/48179165) [深入理解MessageQueue](https://www.jianshu.com/p/8c829dc15950)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看