青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

羅朝輝(飄飄白云)

關注嵌入式操作系統,移動平臺,圖形開發。-->加微博 ^_^

  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
  85 隨筆 :: 0 文章 :: 169 評論 :: 0 Trackbacks
Android多線程分析之四:MessageQueue的實現

羅朝輝 (http://www.shnenglu.com/kesalin/)

本文遵循“署名-非商業用途-保持一致”創作公用協議

在前面兩篇文章《
Android多線程分析之二:Thread的實現》,《Android多線程分析之三:Handler,Looper的實現》中分別介紹了 Thread 的創建,運行,銷毀的過程以及 Thread與 Handler,Looper 之間的關聯:Thread 在其 run() 方法中創建和運行消息處理循環 Looper,而 Looper::loop() 方法不斷地從 MessageQueue 中獲取消息,并由 Handler 分發處理該消息。接下來就來介紹 MessageQueue 的運作機制,MessageQueue。

參考源碼:
android/framework/base/core/java/android/os/MessageQueue.java
android/framework/base/core/java/android/os/Message.java
android/frameworks/base/core/jni/android_os_MessageQueue.h
android/frameworks/base/core/jni/android_os_MessageQueue.cpp

先來看 MessageQueue 的構造函數以及重要的成員變量:
    // True if the message queue can be quit.
    private final boolean mQuitAllowed;
    private int mPtr; // used by native code
    Message mMessages;
    private boolean mQuiting;
    // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
    private boolean mBlocked;

mQuitAllowed: 其含義與 Looper.prepare(boolean quitAllowed) 中參數含義一直,是否允許中止;
mPtr:Android MessageQueue 是通過調用 C++ native MessageQueue 實現的,這個 mPtr 就是指向 native MessageQueue;
mMessages:Message 是鏈表結構的,因此這個變量就代表 Message 鏈表;
mQuiting:是否終止了;
mBlocked:是否正在等待被激活以獲取消息;

MessageQueue 的構造函數很簡單:
    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        nativeInit();
    }

它通過轉調 native 方法 nativeInit() 實現的,后者是定義在 android_os_MessageQueue.cpp 中:
static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
    if (!nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return;
    }

    nativeMessageQueue->incStrong(env);
    android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue);
}
static void android_os_MessageQueue_setNativeMessageQueue(JNIEnv* env, jobject messageQueueObj,
        NativeMessageQueue* nativeMessageQueue) {
    env->SetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr,
             reinterpret_cast<jint>(nativeMessageQueue));
}

nativeInit() 方法創建 NativeMessageQueue 對象,并將這個對象的指針復制給 Android MessageQueue 的 mPtr。NativeMessageQueue 的定義如下:
class MessageQueue : public RefBase {
public:
    /* Gets the message queue's looper. */
    inline sp<Looper> getLooper() const {
        return mLooper;
    }

    bool raiseAndClearException(JNIEnv* env, const char* msg);
    virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj) = 0;
protected:
    MessageQueue();
    virtual ~MessageQueue();
protected:
    sp<Looper> mLooper;
};

class NativeMessageQueue : public MessageQueue {
public:
    NativeMessageQueue();
    virtual ~NativeMessageQueue();
    virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj);
    void pollOnce(JNIEnv* env, int timeoutMillis);
    void wake();

private:
    bool mInCallback;
    jthrowable mExceptionObj;
};

其中值得關注的是 NativeMessageQueue 的構造以及pollOnce,wake 兩個方法,它們是Java MessageQueue 中 nativePollOnce 和 nativeWake 的 native 方法:
NativeMessageQueue::NativeMessageQueue() : mInCallback(false), mExceptionObj(NULL) {
    mLooper = Looper::getForThread();
    if (mLooper == NULL) {
        mLooper = new Looper(false);
        Looper::setForThread(mLooper);
    }
}

void NativeMessageQueue::pollOnce(JNIEnv* env, int timeoutMillis) {
    mInCallback = true;
    mLooper->pollOnce(timeoutMillis);
    mInCallback = false;
}

void NativeMessageQueue::wake() {
    mLooper->wake();
}

在 NativeMessageQueue 的構造函數中,會獲取當前線程的 Looper(注意這是 C++ Looper,定義在frameworks/native/libs/utils/Looper.h 中),如果當前線程還沒有 Looper,就創建一個,并保存在線程的 TLS 中。pollOnce 和 wake 最終都是通過 Linux 的 epoll 模型來實現的。pollOnce() 通過等待被激活,然后從消息隊列中獲取消息;wake() 則是激活處于等待狀態的消息隊列,通知它有消息到達了。這是典型的生產者-消費者模型。

對于Android MessageQueue 來說,其主要的工作就是:接收投遞進來的消息,獲取下一個需要處理的消息。這兩個功能是通過 enqueueMessage() 和 next() 方法實現的。next() 在前一篇文章介紹 Looper.loop() 時提到過。

在分析這兩個函數之前,先來介紹一下 Message:前面說過 Message 是完備的,即它同時帶有消息內容和處理消息的 Handler 或 callback。下面列出它的主要成員變量:
public int what;     // 消息 id
public int arg1;     // 消息參數
public int arg2;     // 消息參數
public Object obj;   // 消息參數
long when;           // 處理延遲時間,由 Handler 的 sendMessageDelayed/postDelayed 設置
Handler target;    // 處理消息的 Handler
Runnable callback;   // 處理消息的回調
Message next;    // 鏈表結構,指向下一個消息

Message 有一些名為 obtain 的靜態方法用于創建 Message,通常我們都是通過 Handler 的 obtain 靜態方法轉調 Message 的靜態方法來創建新的 Message。

接下來分析 enqueueMessage:
    final boolean enqueueMessage(Message msg, long when) {
        if (msg.isInUse()) {
            throw new AndroidRuntimeException(msg + " This message is already in use.");
        }
        if (msg.target == null) {
            throw new AndroidRuntimeException("Message must have a target.");
        }

        boolean needWake;
        synchronized (this) {
            if (mQuiting) {
                return false;
            }

            msg.when = when;
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                
// up the event queue unless there is a barrier at the head of the queue
                
// and the message is the earliest asynchronous message in the queue.
                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;
            }
        }
        if (needWake) {
            nativeWake(mPtr);
        }
        return true;
    }

首先檢測消息的合法性:是否已經在處理中和是否有處理它的Handler,然后判斷 mQuiting 是否中止了,如果沒有則根據消息處理時間排序將消息插入鏈表中的合適位置。在這其中作了一些減少同步操作的優化,即使當前消息隊列已經處于 Blocked 狀態,且隊首是一個消息屏障(和內存屏障的理念一樣,這里是通過 p.target == null 來判斷隊首是否是消息屏障),并且要插入的消息是所有異步消息中最早要處理的才會 needwake 激活消息隊列去獲取下一個消息。Handler 的 post/sendMessage 系列方法最后都是通過轉調 MessageQueue 的 enqueueMessage 來實現的,比如:
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

其實 Handler 中與Message 相關的靜態方法都是通過 MessageQueue 的對應的靜態方法實現的,比如 removeMessages, hasMessages, hasCallbacks 等等,這里就不一一詳述了。至此,已經完整地分析了如何通過 Handler 提交消息到 MessageQueue 中了。

下面來分析如何從 MessageQueue 中獲取合適的消息, 這是 next() 要做的最主要的事情,next() 方法還做了其他一些事情,這些其它事情是為了提高系統效果,利用消息隊列在空閑時通過 idle handler 做一些事情,比如 gc 等等。但它們和獲取消息關系不大,所以這部分將從略介紹。
   final Message next() {
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;

        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            nativePollOnce(mPtr, nextPollTimeoutMillis);

            synchronized (this) {
                if (mQuiting) {
                    return null;
                }

                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // If first time idle, then get the number of idlers to run.
                
// Idle handles only run if the queue is empty or if the first message
                
// in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            
// We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null// release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf("MessageQueue", "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            
// so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }

隊列被激活之后,首先判斷隊首是不是消息屏障,如果是則跳過所有的同步消息,查找最先要處理的異步消息。如果第一個待處理的消息還沒有到要處理的時機則設置激活等待時間;否則這個消息就是需要處理的消息,將該消息設置為 inuse,并將隊列設置為非 blocked 狀態,然后返回該消息。next() 方法是在 Looper.loop() 中被調用的,Looper 在獲得要處理的消息之后就會調用和消息關聯的 Handler 來分發消息,這里再回顧一下:
  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(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            msg.target.dispatchMessage(msg);

            msg.recycle();
        }
    }

如果隊列中沒有消息或者第一個待處理的消息時機未到,且也沒有其他利用隊列空閑要處理的事務,則將隊列設置為設置 blocked 狀態,進入等待狀態;否則就利用隊列空閑處理其它事務。

至此,已經對 Android 多線程相關的主要概念 Thread, HandlerThread, Handler, Looper, Message, MessageQueue 作了一番介紹,下一篇就要講講 AsyncTask,這是為了簡化 UI 多線程編程為提供的一個便利工具類。
posted on 2014-07-14 17:15 羅朝輝 閱讀(2012) 評論(0)  編輯 收藏 引用 所屬分類: 移動開發
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产一级久久| 国产精品美女诱惑| 亚洲精品国产系列| 91久久综合| 欧美日本精品一区二区三区| 99精品国产在热久久婷婷| 一本色道久久综合亚洲精品高清| 国产精品国产三级国产专区53| 香蕉久久夜色精品| 久久久精品tv| 99riav国产精品| 午夜精品国产更新| 亚洲电影免费观看高清完整版在线观看| 欧美激情按摩在线| 欧美三级在线视频| 久久亚洲精品欧美| 欧美日韩1区2区| 久久视频免费观看| 欧美日韩国产在线观看| 欧美中文字幕在线| 欧美成人国产va精品日本一级| 亚洲一区精品在线| 久久尤物视频| 亚洲欧美日韩系列| 麻豆成人小视频| 先锋影音国产一区| 你懂的国产精品| 久久精品国产综合精品| 欧美金8天国| 久久全国免费视频| 国产精品免费在线| 亚洲国产福利在线| 黄色av成人| 亚洲专区欧美专区| 一区二区三区久久| 男女精品视频| 久久深夜福利| 国产片一区二区| 中文在线资源观看网站视频免费不卡| 在线免费观看日韩欧美| 亚洲男人的天堂在线| 99热免费精品| 免费日韩视频| 免费不卡中文字幕视频| 国产女人18毛片水18精品| 99精品国产福利在线观看免费| 一区二区三区在线观看国产| 亚洲欧美日韩中文播放| 在线视频你懂得一区| 欧美二区在线播放| 欧美大片免费观看| 在线成人欧美| 久久蜜臀精品av| 你懂的成人av| 136国产福利精品导航网址应用| 性色一区二区| 久久免费偷拍视频| 国产专区一区| 久久久www成人免费无遮挡大片 | 国内自拍视频一区二区三区| 亚洲午夜精品一区二区三区他趣| 在线亚洲欧美专区二区| 欧美日韩精品国产| 一本到高清视频免费精品| 99精品欧美| 欧美午夜片在线免费观看| 一区二区三区精品国产| 亚洲一区二区精品在线| 国产精品黄色在线观看| 一区二区三区福利| 午夜视频在线观看一区| 国产人久久人人人人爽| 久久国产精品亚洲77777| 久久裸体艺术| 亚洲日本激情| 欧美视频中文字幕| 午夜视频一区在线观看| 久久免费国产精品| 亚洲人成在线观看| 欧美日韩中文字幕在线| 亚洲先锋成人| 欧美成人免费网站| 一区二区三区视频在线| 国产九区一区在线| 久久久久久久久蜜桃| 91久久精品国产| 午夜国产精品视频免费体验区| 国产亚洲一级高清| 欧美va亚洲va香蕉在线| 在线视频精品一区| 美脚丝袜一区二区三区在线观看 | 国产精品日日做人人爱| 久久国产精品毛片| 亚洲精品国产无天堂网2021| 午夜一区二区三视频在线观看| 一区二区视频免费在线观看| 欧美激情视频在线播放| 午夜精彩国产免费不卡不顿大片| 乱中年女人伦av一区二区| 99v久久综合狠狠综合久久| 国产免费亚洲高清| 欧美日本免费| 久久久久久久精| 一区二区动漫| 欧美成人综合在线| 久久成人羞羞网站| 国产精品99久久久久久宅男| 在线观看视频日韩| 国产精品羞羞答答| 欧美激情无毛| 久久久噜噜噜久久久| 亚洲一区二区在线播放| 欧美激情一区二区三区在线视频| 午夜精品影院| 亚洲无线观看| 99精品欧美一区二区三区综合在线| 国产精品私房写真福利视频| 欧美激情中文字幕一区二区| 久久精品久久99精品久久| 亚洲一区二区成人| 亚洲美女av网站| 亚洲第一精品夜夜躁人人爽| 久久理论片午夜琪琪电影网| 欧美一区二区三区的| 亚洲视频在线观看一区| 亚洲美女黄网| 亚洲免费观看高清完整版在线观看熊 | 亚洲一级在线观看| 日韩视频不卡| 亚洲黄网站在线观看| 欧美国产激情| 欧美成人精品不卡视频在线观看| 久久精品亚洲一区二区三区浴池| 亚洲欧美亚洲| 午夜精品久久久久久久白皮肤 | 欧美在线观看视频一区二区三区| 正在播放日韩| 一区二区三区黄色| 一区二区三区四区国产| 一区二区三区高清在线| 一区二区三区视频在线看| 中文在线不卡| 亚洲欧美不卡| 欧美在线视频a| 久久精品91| 毛片av中文字幕一区二区| 久久中文字幕一区| 模特精品在线| 亚洲日本成人女熟在线观看| 亚洲精品一区二区在线| 日韩亚洲成人av在线| 一区二区三区视频在线观看| 亚洲视频在线免费观看| 亚洲欧美久久久| 欧美中文字幕在线| 六月丁香综合| 欧美日韩伊人| 国产亚洲一本大道中文在线| 狠狠色丁香久久婷婷综合_中| 亚洲高清不卡在线| 夜夜嗨av一区二区三区四区| 亚洲综合99| 玖玖综合伊人| 亚洲区一区二| 午夜精品久久久久| 免费一级欧美片在线观看| 欧美区亚洲区| 国产亚洲成年网址在线观看| 91久久国产自产拍夜夜嗨| 一本一本久久a久久精品综合妖精 一本一本久久a久久精品综合麻豆 | 日韩小视频在线观看专区| 亚洲一区二区三区四区中文 | 日韩一级在线观看| 欧美亚洲免费| 亚洲国产精品一区在线观看不卡| 一区二区激情小说| 欧美在线一二三| 欧美精品色一区二区三区| 国产情人节一区| 亚洲美女中出| 久久综合电影一区| 在线一区亚洲| 欧美电影免费观看高清完整版| 国产精品爽爽爽| 日韩一级大片| 久久综合色婷婷| 亚洲线精品一区二区三区八戒| 麻豆成人91精品二区三区| 国产乱码精品| 中日韩美女免费视频网站在线观看| 久久精品国亚洲| 99视频一区| 欧美激情2020午夜免费观看| 黑人巨大精品欧美一区二区| 亚洲男人第一网站| 亚洲日韩第九十九页| 久久婷婷国产麻豆91天堂| 国产模特精品视频久久久久 | 国产主播一区| 欧美一级二区|