Android多线程分析之二:Thread的实现
Android多線程分析之二:Thread的實現
羅朝輝 (http://www.cnblogs.com/kesalin/) CC 許可,轉載請注明出處在前文《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 類中一些關鍵成員變量如下:
接下來,我們來看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 choicethis.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?釋放內存,至此線程就終結了。
?
轉載于:https://www.cnblogs.com/kesalin/p/android_thread_impl.html
總結
以上是生活随笔為你收集整理的Android多线程分析之二:Thread的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 正则表整理
- 下一篇: js 获取时间对象代码