編輯:關於Android編程
在前文《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(); }
/** * 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 }
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:線程 id,通過遞增 count 得到該id,如果沒有顯示給線程設置名字,那麼就會使用 Thread+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); }
public static Thread currentThread() { return VMThread.currentThread(); }
static void Dalvik_java_lang_VMThread_currentThread(const u4* args, JValue* pResult) { UNUSED_PARAMETER(args); RETURN_PTR(dvmThreadSelf()->threadObj); }
Thread* dvmThreadSelf() { return (Thread*) pthread_getspecific(gDvm.pthreadKeySelf); }
/* the java/lang/Thread that we are associated with */ Object* threadObj;
接著分析上面的代碼,如果沒有給新線程指定 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)); } }
上面分析的是 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); } }
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(); }
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; }
然後,通過 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); ... }
public void run() { if (target != null) { target.run(); } }
/* * 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); }
一、Android歷史2003 年 Andy Rubin 創辦 Android 公司2005 年 Google 收購 Android 公司2007 年成立開放手持設備聯盟
引言【轉載請注明出處:從Handler+Message+Looper源碼帶你分析Android系統的消息處理機制 CSDN 廢墟的樹】作為Android開發者,相信很多人
Android開發中視圖和數據的綁定離不開Adapt系列的類,在呈現給用戶的界面友好美觀和內容豐富的應用中視圖為骨,內容為肉,Ad
今天要介紹的是一個Android中使用得比較多的android 事件總線 EventBus模式的一個框架Otto。Otto 官網:http://square.github