• <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>

            羅朝輝(飄飄白云)

            關(guān)注嵌入式操作系統(tǒng),移動(dòng)平臺(tái),圖形開發(fā)。-->加微博 ^_^

              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              85 隨筆 :: 0 文章 :: 169 評(píng)論 :: 0 Trackbacks
            Android多線程分析之二:Thread的實(shí)現(xiàn)

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

            本文遵循“署名-非商業(yè)用途-保持一致”創(chuàng)作公用協(xié)議

            在前文《Android多線程分析之一:使用Thread異步下載圖像》中演示了如何使用 Thread 處理異步事務(wù)。示例中這個(gè) Java Thread 類都是位于 Framework 層的類,它自身是通過(guò) JNI 轉(zhuǎn)調(diào) dalvik 里面的 Thread 相關(guān)方法實(shí)現(xiàn)的。因此要分析 Androd 中的線程,就需要分析這兩層中的與線程相關(guān)的代碼,這就是本文要探討的主題。本文將把 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

            首先來(lái)分析 Android Thread,這個(gè)類的源碼在android/libcore/luni/src/main/java/java/lang/Thread.java,它實(shí)現(xiàn)了 Runnable 接口。Runnable 只有一個(gè)無(wú)參無(wú)返回值的 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 存在六種狀態(tài),這些狀態(tài)定義在枚舉 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 類中一些關(guān)鍵成員變量如下:
                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:可視為對(duì) dalvik thread 的簡(jiǎn)單封裝,Thread 類通過(guò) VMThread 里面的 JNI 方法來(lái)調(diào)用 dalvik 中操作線程的方法,通過(guò)它的成員變量 thread 和 vmata,我們可以將 Android Thread 和 dalvik Thread 的關(guān)聯(lián)起來(lái);
            group:每一個(gè)線程都屬于一個(gè)group,當(dāng)線程被創(chuàng)建時(shí)就會(huì)加入一個(gè)特定的group,當(dāng)線程運(yùn)行結(jié)束,會(huì)從這個(gè) group 中移除;
            daemon:當(dāng)前線程是不是守護(hù)線程,守護(hù)線程只會(huì)在沒有非守護(hù)線程運(yùn)行的情況下才會(huì)運(yùn)行;
            priority:線程優(yōu)先級(jí),Java Thread 類的線程優(yōu)先級(jí)取值范圍為 [1, 10],默認(rèn)優(yōu)先級(jí)為 5;
            stackSize:線程棧大小,默認(rèn)為 0,即使用默認(rèn)的線程棧大小(由 dalvik 中的全局變量 gDvm.stackSize 決定);
            target:一個(gè) Runnable 對(duì)象,Thread 的 run() 方法中會(huì)轉(zhuǎn)掉該 target 的 run() 方法,這是線程真正處理事務(wù)的地方;
            id:Android 線程 id,通過(guò)遞增 count 得到該 id,如果沒有顯示給線程設(shè)置名字,那么就會(huì)使用 Thread+id 當(dāng)作線程的名字。注意這不是真正意義上的線程 id,即在 logcat 中打印的 tid 并不是這個(gè) id,那 tid 是指 dalvik 線程的 id;
            localValues:線程本地存儲(chǔ)(TLS)數(shù)據(jù);

            接下來(lái),我們來(lái)看Android Thread 的構(gòu)造函數(shù),大部分構(gòu)造函數(shù)都是通過(guò)轉(zhuǎn)調(diào)靜態(tài)函數(shù) create 實(shí)現(xiàn)的,下面來(lái)詳細(xì)分析 create 這個(gè)關(guān)鍵函數(shù):
                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);
                }

            首先,通過(guò)靜態(tài)函數(shù) currentThread 獲取創(chuàng)建線程所在的當(dāng)前線程,然后將當(dāng)前線程的一些屬性傳遞給即將創(chuàng)建的新線程。這是通過(guò) VMThread 轉(zhuǎn)調(diào) dalvik 中的代碼實(shí)現(xiàn)的。
                public static Thread currentThread() {
                    return VMThread.currentThread();
                }

            VMThread 的 currentThread 是一個(gè) native 方法,其 JNI 實(shí)現(xiàn)為 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);
            }

            從上面的調(diào)用棧可以看到,每一個(gè) dalvik 線程都會(huì)將自身存放在key 為 pthreadKeySelf 的線程本地存儲(chǔ)中,獲取當(dāng)前線程時(shí),只需要根據(jù)這個(gè) key 查詢獲取即可,dalvik Thread 有一個(gè)名為 threadObj 的成員變量:
                /* the java/lang/Thread that we are associated with */
                Object*     threadObj;

            dalvik Thread 這個(gè)成員變量 threadObj 關(guān)聯(lián)的就是對(duì)應(yīng)的 Android Thread 對(duì)象,所以通過(guò) native 方法 VMThread.currentThread() 返回的是存儲(chǔ)在 TLS 中的當(dāng)前 dalvik 線程對(duì)應(yīng)的 Android Thread。

            接著分析上面的代碼,如果沒有給新線程指定 group 那么就會(huì)指定 group 為當(dāng)前線程所在的 group 中,然后給新線程設(shè)置 name,priority 等。最后通過(guò)調(diào)用 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 的代碼相對(duì)簡(jiǎn)單,它有一個(gè)名為 threadRefs 的列表,持有屬于同一組的 thread 引用,可以對(duì)一組 thread 進(jìn)行一些線程操作。

            上面分析的是 Android Thread 的構(gòu)造過(guò)程,從上面的分析可以看出,Android Thread 的構(gòu)造方法僅僅是設(shè)置了一些線程屬性,并沒有真正去創(chuàng)建一個(gè)新的 dalvik Thread,dalvik Thread 創(chuàng)建過(guò)程要等到客戶代碼調(diào)用 Android Thread 的 start() 方法才會(huì)進(jìn)行。下面我們來(lái)分析 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 方法很簡(jiǎn)單,僅僅是轉(zhuǎn)調(diào) VMThread 的 native 方法 create,其 JNI 實(shí)現(xiàn)為 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 的實(shí)現(xiàn)在 Thread.cpp 中,由于這個(gè)函數(shù)的內(nèi)容很長(zhǎng),在這里只列出關(guān)鍵的地方:
            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;
            }

            首先,通過(guò)調(diào)用 allocThread 創(chuàng)建一個(gè)名為 newThread 的 dalvik Thread  并設(shè)置一些屬性,將設(shè)置其成員變量 threadObj 為傳入的 Android Thread,這樣 dalvik Thread 就與Android Thread 關(guān)聯(lián)起來(lái)了;然后創(chuàng)建一個(gè)名為 vmThreadObj 的 VMThread 對(duì)象,設(shè)置其成員變量 vmData 為 newThread,設(shè)置 Android Thread threadObj 的成員變量 vmThread 為這個(gè) vmThreadObj,這樣 Android Thread 通過(guò) VMThread 的成員變量 vmData 就和 dalvik Thread 關(guān)聯(lián)起來(lái)了。

            然后,通過(guò) pthread_create 創(chuàng)建 pthread 線程,并讓這個(gè)線程 start,這樣就會(huì)進(jìn)入該線程的 thread entry 運(yùn)行,下來(lái)我們來(lái)看新線程的 thread entry 方法 interpThreadStart,同樣只列出關(guān)鍵的地方:
            /*
             * 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 中,首先設(shè)置線程的名字,然后通過(guò)調(diào)用 prepareThread 設(shè)置線程 id 以及其它一些屬性,并調(diào)用 setThreadSelf 將新 dalvik Thread 自身保存在 TLS 中,這樣之后就能通過(guò)  dvmThreadSelf 方法從 TLS 中獲取它。然后修改狀態(tài)為 THREAD_RUNNING,并調(diào)用對(duì)應(yīng) Android Thread 的 run() 方法,運(yùn)行客戶代碼:
                public void run() {
                    if (target != null) {
                        target.run();
                    }
                }

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

            target 在前面已經(jīng)做了介紹,它是線程真正處理邏輯事務(wù)的地方。一旦邏輯事務(wù)處理完畢從 run 中返回,線程就會(huì)回到 interpThreadStart 方法中,繼續(xù)執(zhí)行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 函數(shù)里,首先獲取當(dāng)前線程 self,這里獲得的就是當(dāng)前執(zhí)行 thread entry 的新線程,然后通過(guò)其對(duì)應(yīng)的 Android Thread 對(duì)象 threadObj 獲取該對(duì)象所在 group,然后將 threadObj 這個(gè) Android Thread 對(duì)象從 group 中移除;接著清除 Android 與 dalvik 線程之間的關(guān)聯(lián)關(guān)系,并通知 join 該線程的其它線程;最后,設(shè)置線程狀態(tài)為 THREAD_ZOMBIE,清除 TLS 中存儲(chǔ)的線程值,并通過(guò)調(diào)用 freeThread 釋放內(nèi)存,至此線程就終結(jié)了。



            posted on 2014-07-11 10:29 羅朝輝 閱讀(6494) 評(píng)論(1)  編輯 收藏 引用 所屬分類: 移動(dòng)開發(fā)

            評(píng)論

            # re: Android多線程分析之二:Thread的實(shí)現(xiàn) 2014-07-11 15:11 java學(xué)習(xí)
            好像和java一樣的丫  回復(fù)  更多評(píng)論
              

            亚洲中文字幕无码久久精品1| 一本一道久久综合狠狠老| 亚洲国产美女精品久久久久∴| 国产日韩久久免费影院| 99久久www免费人成精品| 久久精品国产亚洲麻豆| 99久久无码一区人妻a黑| 久久精品国产亚洲AV无码偷窥 | 欧美va久久久噜噜噜久久| 理论片午午伦夜理片久久| 色悠久久久久久久综合网| 久久婷婷五月综合97色直播| 蜜臀久久99精品久久久久久| 亚洲国产香蕉人人爽成AV片久久| 久久综合五月丁香久久激情| 午夜精品久久久久久影视riav | 久久精品国产亚洲AV影院| 久久综合视频网| 97精品伊人久久久大香线蕉| 日韩精品无码久久久久久| 国产精品免费看久久久| 国产美女久久久| 久久精品国产精品亜洲毛片| 伊人久久大香线蕉无码麻豆| 日日躁夜夜躁狠狠久久AV| 久久精品草草草| 欧美日韩精品久久久久| 一本色道久久99一综合| 精品综合久久久久久97超人| 国产精品美女久久久久av爽| 欧美日韩精品久久免费| 99999久久久久久亚洲| 久久久久无码中| 欧洲精品久久久av无码电影| 老司机国内精品久久久久| 无码人妻少妇久久中文字幕 | 91精品国产高清91久久久久久| 日本道色综合久久影院| 久久久久波多野结衣高潮| 久久青青草原国产精品免费| 国产精品久久久久久五月尺|