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

羅朝輝(飄飄白云)

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

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

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

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

在前文《Android多線程分析之一:使用Thread異步下載圖像》中演示了如何使用 Thread 處理異步事務。示例中這個 Java Thread 類都是位于 Framework 層的類,它自身是通過 JNI 轉調 dalvik 里面的 Thread 相關方法實現的。因此要分析 Androd 中的線程,就需要分析這兩層中的與線程相關的代碼,這就是本文要探討的主題。本文將把 Framework 層中的 Java Thread 稱為 Android 線程/Thread,而把 dalvik 中的  Thread 成為 dalvik 線程/Thread。 

本文涉及到的 Android 源碼路徑:
android/libcore/luni/src/main/java/java/lang/Runnable.java
android/libcore/luni/src/main/java/java/lang/Thread.java
android/libcore/luni/src/main/java/java/lang/ThreadGroup.java
android/libcore/luni/src/main/java/java/lang/VMThread.java
android/dalvik/vm/native/java_lang_VMThread.cpp
android/dalvik/vm/Thread.cpp

首先來分析 Android Thread,這個類的源碼在android/libcore/luni/src/main/java/java/lang/Thread.java,它實現了 Runnable 接口。Runnable 只有一個無參無返回值的 void run() 的接口:
/**
 * Represents a command that can be executed. Often used to run code in a
 * different {@link Thread}.
 
*/
public interface Runnable {
    /**
     * Starts executing the active part of the class' code. This method is
     * called when a thread is started that has been created with a class which
     * implements {@code Runnable}.
     
*/
    public void run();
}

Android Thread 存在六種狀態,這些狀態定義在枚舉 State 中,源碼注釋寫的很清晰,在這里就不羅嗦了: 
    /**
     * A representation of a thread's state. A given thread may only be in one
     * state at a time.
     
*/
    public enum State {
        /**
         * The thread has been created, but has never been started.
         
*/
        NEW,
        /**
         * The thread may be run.
         
*/
        RUNNABLE,
        /**
         * The thread is blocked and waiting for a lock.
         
*/
        BLOCKED,
        /**
         * The thread is waiting.
         
*/
        WAITING,
        /**
         * The thread is waiting for a specified amount of time.
         
*/
        TIMED_WAITING,
        /**
         * The thread has been terminated.
         
*/
        TERMINATED
    }

Android Thread 類中一些關鍵成員變量如下:
    volatile VMThread vmThread;
    volatile ThreadGroup group;
    volatile boolean daemon;    
    volatile String name;
    volatile int priority;
    volatile long stackSize;
    Runnable target;
    private static int count = 0;
    private long id;
    ThreadLocal.Values localValues;

vmThread:可視為對 dalvik thread 的簡單封裝,Thread 類通過 VMThread 里面的 JNI 方法來調用 dalvik 中操作線程的方法,通過它的成員變量 thread 和 vmata,我們可以將 Android Thread 和 dalvik Thread 的關聯起來;
group:每一個線程都屬于一個group,當線程被創建時就會加入一個特定的group,當線程運行結束,會從這個 group 中移除;
daemon:當前線程是不是守護線程,守護線程只會在沒有非守護線程運行的情況下才會運行;
priority:線程優先級,Java Thread 類的線程優先級取值范圍為 [1, 10],默認優先級為 5;
stackSize:線程棧大小,默認為 0,即使用默認的線程棧大小(由 dalvik 中的全局變量 gDvm.stackSize 決定);
target:一個 Runnable 對象,Thread 的 run() 方法中會轉掉該 target 的 run() 方法,這是線程真正處理事務的地方;
id:Android 線程 id,通過遞增 count 得到該 id,如果沒有顯示給線程設置名字,那么就會使用 Thread+id 當作線程的名字。注意這不是真正意義上的線程 id,即在 logcat 中打印的 tid 并不是這個 id,那 tid 是指 dalvik 線程的 id;
localValues:線程本地存儲(TLS)數據;

接下來,我們來看Android Thread 的構造函數,大部分構造函數都是通過轉調靜態函數 create 實現的,下面來詳細分析 create 這個關鍵函數:
    private void create(ThreadGroup group, Runnable runnable, String threadName, long stackSize) {
        Thread currentThread = Thread.currentThread();
        if (group == null) {
            group = currentThread.getThreadGroup();
        }

        if (group.isDestroyed()) {
            throw new IllegalThreadStateException("Group already destroyed");
        }

        this.group = group;

        synchronized (Thread.class) {
            id = ++Thread.count;
        }

        if (threadName == null) {
            this.name = "Thread-" + id;
        } else {
            this.name = threadName;
        }

        this.target = runnable;
        this.stackSize = stackSize;

        this.priority = currentThread.getPriority();

        this.contextClassLoader = currentThread.contextClassLoader;

        // Transfer over InheritableThreadLocals.
        if (currentThread.inheritableValues != null) {
            inheritableValues = new ThreadLocal.Values(currentThread.inheritableValues);
        }

        // add ourselves to our ThreadGroup of choice
        this.group.addThread(this);
    }

首先,通過靜態函數 currentThread 獲取創建線程所在的當前線程,然后將當前線程的一些屬性傳遞給即將創建的新線程。這是通過 VMThread 轉調 dalvik 中的代碼實現的。
    public static Thread currentThread() {
        return VMThread.currentThread();
    }

VMThread 的 currentThread 是一個 native 方法,其 JNI 實現為 android/dalvik/vm/native/java_lang_VMThread.cpp 中的 Dalvik_java_lang_VMThread_currentThread 方法:
static void Dalvik_java_lang_VMThread_currentThread(const u4* args,
    JValue* pResult)
{
    UNUSED_PARAMETER(args);

    RETURN_PTR(dvmThreadSelf()->threadObj);
}

該方法里的 dvmThreadSelf() 方法定義在 android/dalvik/vm/Thread.cpp 中:
Thread* dvmThreadSelf()
{
    return (Thread*) pthread_getspecific(gDvm.pthreadKeySelf);
}

從上面的調用棧可以看到,每一個 dalvik 線程都會將自身存放在key 為 pthreadKeySelf 的線程本地存儲中,獲取當前線程時,只需要根據這個 key 查詢獲取即可,dalvik Thread 有一個名為 threadObj 的成員變量:
    /* the java/lang/Thread that we are associated with */
    Object*     threadObj;

dalvik Thread 這個成員變量 threadObj 關聯的就是對應的 Android Thread 對象,所以通過 native 方法 VMThread.currentThread() 返回的是存儲在 TLS 中的當前 dalvik 線程對應的 Android Thread。

接著分析上面的代碼,如果沒有給新線程指定 group 那么就會指定 group 為當前線程所在的 group 中,然后給新線程設置 name,priority 等。最后通過調用 ThreadGroup 的 addThread 方法將新線程添加到 group 中:

    /**
     * Called by the Thread constructor.
     
*/
    final void addThread(Thread thread) throws IllegalThreadStateException {
        synchronized (threadRefs) {
            if (isDestroyed) {
                throw new IllegalThreadStateException();
            }
            threadRefs.add(new WeakReference<Thread>(thread));
        }
    }

ThreadGroup 的代碼相對簡單,它有一個名為 threadRefs 的列表,持有屬于同一組的 thread 引用,可以對一組 thread 進行一些線程操作。

上面分析的是 Android Thread 的構造過程,從上面的分析可以看出,Android Thread 的構造方法僅僅是設置了一些線程屬性,并沒有真正去創建一個新的 dalvik Thread,dalvik Thread 創建過程要等到客戶代碼調用 Android Thread 的 start() 方法才會進行。下面我們來分析 Java Thread 的 start() 方法:
public synchronized void start() {

        if (hasBeenStarted) {
            throw new IllegalThreadStateException("Thread already started."); // TODO Externalize?
        }

        hasBeenStarted = true;

        VMThread.create(this, stackSize);
    }
}

Android Thread 的 start 方法很簡單,僅僅是轉調 VMThread 的 native 方法 create,其 JNI 實現為 android/dalvik/vm/native/java_lang_VMThread.cpp 中的 Dalvik_java_lang_VMThread_create 方法:
static void Dalvik_java_lang_VMThread_create(const u4* args, JValue* pResult)
{
    Object* threadObj = (Object*) args[0];
    s8 stackSize = GET_ARG_LONG(args, 1);

    /* copying collector will pin threadObj for us since it was an argument */
    dvmCreateInterpThread(threadObj, (int) stackSize);
    RETURN_VOID();
}

dvmCreateInterpThread 的實現在 Thread.cpp 中,由于這個函數的內容很長,在這里只列出關鍵的地方:
bool dvmCreateInterpThread(Object* threadObj, int reqStackSize)
{
    Thread* self = dvmThreadSelf();
    
    Thread* newThread = allocThread(stackSize); 
    newThread->threadObj = threadObj;
    
    Object* vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_DEFAULT);
    dvmSetFieldInt(vmThreadObj, gDvm.offJavaLangVMThread_vmData, (u4)newThread);
    dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread, vmThreadObj);
    
    pthread_t threadHandle;
    int cc = pthread_create(&threadHandle, &threadAttr, interpThreadStart, newThread);

    /*
     * Tell the new thread to start.
     *
     * We must hold the thread list lock before messing with another thread.
     * In the general case we would also need to verify that newThread was
     * still in the thread list, but in our case the thread has not started
     * executing user code and therefore has not had a chance to exit.
     *
     * We move it to VMWAIT, and it then shifts itself to RUNNING, which
     * comes with a suspend-pending check.
     
*/
    dvmLockThreadList(self);

    assert(newThread->status == THREAD_STARTING);
    newThread->status = THREAD_VMWAIT;
    pthread_cond_broadcast(&gDvm.threadStartCond);

    dvmUnlockThreadList();
    
}

/*
 * Alloc and initialize a Thread struct.
 *
 * Does not create any objects, just stuff on the system (malloc) heap.
 
*/
static Thread* allocThread(int interpStackSize)
{
    Thread* thread;
    thread = (Thread*) calloc(1, sizeof(Thread));
    
    thread->status = THREAD_INITIALIZING;
}

首先,通過調用 allocThread 創建一個名為 newThread 的 dalvik Thread  并設置一些屬性,將設置其成員變量 threadObj 為傳入的 Android Thread,這樣 dalvik Thread 就與Android Thread 關聯起來了;然后創建一個名為 vmThreadObj 的 VMThread 對象,設置其成員變量 vmData 為 newThread,設置 Android Thread threadObj 的成員變量 vmThread 為這個 vmThreadObj,這樣 Android Thread 通過 VMThread 的成員變量 vmData 就和 dalvik Thread 關聯起來了。

然后,通過 pthread_create 創建 pthread 線程,并讓這個線程 start,這樣就會進入該線程的 thread entry 運行,下來我們來看新線程的 thread entry 方法 interpThreadStart,同樣只列出關鍵的地方:
/*
 * pthread entry function for threads started from interpreted code.
 
*/
static void* interpThreadStart(void* arg)
{
    Thread* self = (Thread*) arg;

    std::string threadName(dvmGetThreadName(self));
    setThreadName(threadName.c_str());

    /*
     * Finish initializing the Thread struct.
     
*/
    dvmLockThreadList(self);
    prepareThread(self);

    while (self->status != THREAD_VMWAIT)
        pthread_cond_wait(&gDvm.threadStartCond, &gDvm.threadListLock);

    dvmUnlockThreadList();

    /*
     * Add a JNI context.
     
*/
    self->jniEnv = dvmCreateJNIEnv(self);

    /*
     * Change our state so the GC will wait for us from now on.  If a GC is
     * in progress this call will suspend us.
     
*/
    dvmChangeStatus(self, THREAD_RUNNING);

    /*
     * Execute the "run" method.
     *
     * At this point our stack is empty, so somebody who comes looking for
     * stack traces right now won't have much to look at.  This is normal.
     
*/
    Method* run = self->threadObj->clazz->vtable[gDvm.voffJavaLangThread_run];
    JValue unused;

    ALOGV("threadid=%d: calling run()", self->threadId);
    assert(strcmp(run->name, "run") == 0);
    dvmCallMethod(self, run, self->threadObj, &unused);
    ALOGV("threadid=%d: exiting", self->threadId);

    /*
     * Remove the thread from various lists, report its death, and free
     * its resources.
     
*/
    dvmDetachCurrentThread();

    return NULL;
}

/*
 * Finish initialization of a Thread struct.
 *
 * This must be called while executing in the new thread, but before the
 * thread is added to the thread list.
 *
 * NOTE: The threadListLock must be held by the caller (needed for
 * assignThreadId()).
 
*/
static bool prepareThread(Thread* thread)
{
    assignThreadId(thread);
    thread->handle = pthread_self();
    thread->systemTid = dvmGetSysThreadId();

    setThreadSelf(thread);
    

    return true;
}

/*
 * Explore our sense of self.  Stuffs the thread pointer into TLS.
 
*/
static void setThreadSelf(Thread* thread)
{
    int cc;

    cc = pthread_setspecific(gDvm.pthreadKeySelf, thread);
    
}

在新線程的 thread entry 方法 interpThreadStart 中,首先設置線程的名字,然后通過調用 prepareThread 設置線程 id 以及其它一些屬性,并調用 setThreadSelf 將新 dalvik Thread 自身保存在 TLS 中,這樣之后就能通過  dvmThreadSelf 方法從 TLS 中獲取它。然后修改狀態為 THREAD_RUNNING,并調用對應 Android Thread 的 run() 方法,運行客戶代碼:
    public void run() {
        if (target != null) {
            target.run();
        }
    }

對于繼承自 Android Thread 帶有 Looper 的 Android HandlerThread 來說,會調用它覆寫 run 方法():(關于 Looper 的話題下一篇會講到,這里暫且略過)
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

target 在前面已經做了介紹,它是線程真正處理邏輯事務的地方。一旦邏輯事務處理完畢從 run 中返回,線程就會回到 interpThreadStart 方法中,繼續執行dvmDetachCurrentThread 方法:
/*
 * Detach the thread from the various data structures, notify other threads
 * that are waiting to "join" it, and free up all heap-allocated storage.
 * /
void dvmDetachCurrentThread()
{
    Thread* self = dvmThreadSelf();
    Object* vmThread;
    Object* group;
    
    group = dvmGetFieldObject(self->threadObj, gDvm.offJavaLangThread_group);

    /*
     * Remove the thread from the thread group.
     
*/
    if (group != NULL) {
        Method* removeThread =
            group->clazz->vtable[gDvm.voffJavaLangThreadGroup_removeThread];
        JValue unused;
        dvmCallMethod(self, removeThread, group, &unused, self->threadObj);
    }

    /*
     * Clear the vmThread reference in the Thread object.  Interpreted code
     * will now see that this Thread is not running.  As this may be the
     * only reference to the VMThread object that the VM knows about, we
     * have to create an internal reference to it first.
     
*/
    vmThread = dvmGetFieldObject(self->threadObj,
                    gDvm.offJavaLangThread_vmThread);
    dvmAddTrackedAlloc(vmThread, self);
    dvmSetFieldObject(self->threadObj, gDvm.offJavaLangThread_vmThread, NULL);

    /* clear out our struct Thread pointer, since it's going away */
    dvmSetFieldObject(vmThread, gDvm.offJavaLangVMThread_vmData, NULL);

    

    /*
     * Thread.join() is implemented as an Object.wait() on the VMThread
     * object.  Signal anyone who is waiting.
     
*/
    dvmLockObject(self, vmThread);
    dvmObjectNotifyAll(self, vmThread);
    dvmUnlockObject(self, vmThread);

    dvmReleaseTrackedAlloc(vmThread, self);
    vmThread = NULL;

    

    dvmLockThreadList(self);

    /*
     * Lose the JNI context.
     
*/
    dvmDestroyJNIEnv(self->jniEnv);
    self->jniEnv = NULL;

    self->status = THREAD_ZOMBIE;

    /*
     * Remove ourselves from the internal thread list.
     
*/
    unlinkThread(self);

    

    releaseThreadId(self);
    dvmUnlockThreadList();

    setThreadSelf(NULL);

    freeThread(self);
}

/*
 * Free a Thread struct, and all the stuff allocated within.
 
*/
static void freeThread(Thread* thread)
{
    
    free(thread);
}

在 dvmDetachCurrentThread 函數里,首先獲取當前線程 self,這里獲得的就是當前執行 thread entry 的新線程,然后通過其對應的 Android Thread 對象 threadObj 獲取該對象所在 group,然后將 threadObj 這個 Android Thread 對象從 group 中移除;接著清除 Android 與 dalvik 線程之間的關聯關系,并通知 join 該線程的其它線程;最后,設置線程狀態為 THREAD_ZOMBIE,清除 TLS 中存儲的線程值,并通過調用 freeThread 釋放內存,至此線程就終結了。



posted on 2014-07-11 10:29 羅朝輝 閱讀(6534) 評論(1)  編輯 收藏 引用 所屬分類: 移動開發

評論

# re: Android多線程分析之二:Thread的實現 2014-07-11 15:11 java學習
好像和java一樣的丫  回復  更多評論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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天堂| 久久久精品性| 一区二区免费看| 午夜精品区一区二区三| 永久域名在线精品| 亚洲欧洲精品成人久久奇米网| 欧美激情一区在线观看| 亚洲免费在线观看视频| 久久久精品欧美丰满| 亚洲精选中文字幕| 香蕉av福利精品导航| 亚洲国产一区二区精品专区| 一本色道久久综合狠狠躁篇的优点| 国产精品日韩欧美一区二区| 蜜桃av一区二区| 欧美日韩在线不卡一区| 久久女同精品一区二区| 欧美日韩三区| 欧美a级片网| 国产精品久久久久久久久免费桃花| 欧美另类99xxxxx| 久久久综合激的五月天| 欧美日韩中文字幕日韩欧美| 亚洲国产第一| 日韩亚洲欧美综合| 欧美视频在线观看免费| 欧美一区二区视频在线观看| 性8sex亚洲区入口| 99国内精品| 久久久久五月天| 亚洲专区欧美专区| 欧美电影打屁股sp| 久久综合给合| 国产精品日韩一区二区| 亚洲精品乱码久久久久久日本蜜臀 | av成人天堂| 亚洲免费在线视频一区 二区| 激情亚洲一区二区三区四区| 亚洲性夜色噜噜噜7777| 日韩视频一区二区在线观看| 久久精品色图| 久久天天躁狠狠躁夜夜av| 国产精品久久久久久久9999| 欧美一区亚洲二区| 99pao成人国产永久免费视频| 韩国成人精品a∨在线观看| 亚洲一区二区三区午夜| 一区二区三区高清视频在线观看| 你懂的网址国产 欧美| 久久噜噜噜精品国产亚洲综合| 国产精品乱子乱xxxx| 一本久久知道综合久久| 中文国产成人精品久久一| 欧美韩日视频| 亚洲日本电影在线| 一区二区黄色| 欧美性猛交xxxx乱大交蜜桃| 日韩午夜在线观看视频| 亚洲手机视频| 国产精品99一区二区| 一区二区欧美激情| 亚洲欧美日韩综合一区| 国产精品久久久久aaaa樱花| 亚洲影院高清在线| 久久精品国产亚洲一区二区三区| 国产日韩一区二区三区在线播放| 亚洲欧美日韩精品一区二区 | 国产一区日韩二区欧美三区| 性高湖久久久久久久久| 另类成人小视频在线| 亚洲国产高清在线观看视频| 欧美国产日本韩| 亚洲日本电影| 欧美一区二区三区免费在线看| 国产亚洲一级| 欧美ed2k| 亚洲一本大道在线| 久久夜色精品国产噜噜av| 亚洲国产欧美不卡在线观看| 欧美久久久久久久| 亚洲欧美日韩在线播放| 蜜桃久久av一区| 一二三区精品福利视频| 国产日产精品一区二区三区四区的观看方式 | 国产精品视频免费观看| 亚洲一区二区三区乱码aⅴ| 欧美有码在线视频| 亚洲成人中文| 欧美三级精品| 久久久国际精品| 日韩午夜电影| 麻豆精品一区二区综合av | 欧美色视频在线| 久久精品国产精品亚洲精品| 亚洲日本欧美日韩高观看| 欧美与黑人午夜性猛交久久久| 亚洲国产片色| 国产欧美日韩不卡| 欧美人成网站| 久久手机免费观看| 亚洲一区二区三区在线看| 欧美成人r级一区二区三区| 亚洲一区欧美二区| 亚洲欧洲一区二区三区| 国产一区二区三区在线观看视频| 欧美激情视频一区二区三区免费| 香蕉久久夜色| 亚洲人成在线播放| 免费欧美视频| 久久精品人人爽| 亚洲欧美国产视频| 一区二区久久久久久| …久久精品99久久香蕉国产| 国产日韩精品综合网站| 欧美日韩日本视频| 欧美激情亚洲精品| 美女免费视频一区| 久久av老司机精品网站导航| 亚洲自拍偷拍网址| 一本高清dvd不卡在线观看| 欧美wwwwww| 美女视频一区免费观看| 久久大综合网| 久久都是精品| 久久av一区二区三区漫画| 亚洲在线播放| 亚洲男人第一av网站| 亚洲性xxxx| 亚洲一区二区三区国产| 一本综合久久| 亚洲午夜久久久久久久久电影网| 亚洲精品乱码久久久久久| 亚洲国产精品久久久久婷婷老年| 激情亚洲网站| 在线日韩中文字幕| 亚洲第一页自拍| 亚洲激情啪啪| 亚洲人成在线播放| 日韩午夜激情电影| 一本色道久久综合亚洲二区三区 | 99精品视频一区二区三区| 日韩天堂在线观看| 亚洲最新视频在线播放| 亚洲一品av免费观看| 亚洲欧美一区二区三区久久| 亚洲欧美日韩精品久久久久| 香蕉国产精品偷在线观看不卡| 亚洲欧美成人综合| 久久精品视频va| 老司机午夜精品视频在线观看| 欧美高清在线精品一区| 亚洲青涩在线| 亚洲在线观看| 久久精品在线免费观看| 欧美高清在线| 国产精品一二| 在线成人国产| 一区二区三区欧美| 欧美在线不卡视频| 欧美成人久久| 亚洲视频网站在线观看| 久久9热精品视频| 欧美国产精品日韩| 国产精品素人视频| 在线观看亚洲一区| 国产精品99久久不卡二区 | 日韩一级网站| 欧美一区二区精品在线| 欧美激情亚洲一区| 亚洲欧美综合v| 欧美成人一二三| 国产精品永久免费观看| 亚洲国产免费看| 久久成人羞羞网站| 亚洲伦伦在线| 久久久午夜视频| 国产精品久线观看视频| 亚洲电影免费| 欧美一二三视频| 亚洲精品欧美极品| 久久久免费观看视频| 国产精品乱码妇女bbbb| 亚洲黄色视屏| 久久精品天堂| 亚洲一区二区三区国产| 欧美激情bt| 亚洲福利在线看| 久久精品九九| 亚洲一区二区精品视频| 欧美精品一区二区三区在线播放| 韩日成人在线| 久久av资源网站| 亚洲图片欧美日产| 欧美日韩精品在线观看| 亚洲国产成人久久|