一:進程和線程的由來
進程是計算機科技發展的過程的產物。
最早計算機發明出來,是為了解決數學計算而發明的。每解決一個問題,就要打紙帶,也就是打點。
后來人們發現可以批量的設置命令,由計算機讀取這些命令,並挨個執行。
在使用的過程中,有一個問題,如果要做I/O操作,是非常耗時的,這個時候CPU是閑着的,這對於計算機資源是一個巨大的浪費。
於是,人們發明了進程這個東西。每個程序就是一個進程,由操作系統管理,當進行復雜的耗時操作是,CPU可以調度處理其他的進程,從而是性能在整體上提高。
線程的目的:
當CPU調度的某個進程時,該進程正在做網絡操作,這個時候,如果用戶點擊某個按鈕,是無法及時響應的,體驗非常不好。於是,比進程更“小”的調度單位出現了----線程。
我把與用於響應的操作放在一個線程,把耗時的操作放在其他線程,這個用戶可以看到界面快速的響應,沒有延時的效果。
這也是anroid等現在主流操作系統的編程范式:
把UI操作綁定的主線程,由工作線程處理其他的任務。主要是耗時的任務。
二:線程的啟動過程
創建和啟動一個新線程,無論經過多少層的封裝,最終的目的就是由操作系統提供的api來完成。
以下就是從java thread出發,層層分析,一直到linux的pthread結束。
Thread源碼位於:
libcore\libdvm\src\main\java\java\lang\Thread.java
public class Thread implements Runnable {
可見thread是實現了一個runnable接口。
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();
}
runnable什么也沒有,就是run函數。
所以線程的根本就是 創建一個新的線程,運行run方法。
下面我們看看創建線程的過程。
public Thread() {
create(null, null, null, 0);
}
public Thread(Runnable runnable) {
create(null, runnable, null, 0);
}
如上所示,常見的應用中使用thread的方法就是
a.定義一個新thread子類,實現run方法。
b.直接傳遞run給thread作為參數。
接下去我們看下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(); }
VmThread源碼位於:
VMThread 的 currentThread 是一個 native 方法,其 JNI 實現為 android/dalvik/vm/native/java_lang_VMThread.cpp 中
static void Dalvik_java_lang_VMThread_currentThread(const u4* args, JValue* pResult) { UNUSED_PARAMETER(args); RETURN_PTR(dvmThreadSelf()->threadObj); }
這里有個dvmThreadSelf()方法:
Thread* dvmThreadSelf() { return (Thread*) pthread_getspecific(gDvm.pthreadKeySelf); }
可見這是一個存放在key為pthreadKeySelf的索引。
/* the java/lang/Thread that we are associated with */ Object* threadObj;
threadObj關聯的就是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)); } }
threadRefs里面就是存放group對每一個thread的引用。
通過以上代碼分析,thread構造方法僅僅只是設置了一些線程屬性,並沒有創建真正的線程。
Thread新創建的線程:
public synchronized void start() { checkNotStarted(); 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函數很長,但是它做了最重要的一件事:
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 threadobj.
創建vmThreadObj名字的Vmthread對象。
dvmSetFieldInt(vmThreadObj, gDvm.offJavaLangVMThread_vmData, (u4)newThread);
dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread, vmThreadObj);
把vmThreadObj的VM_data方法設置成newThread。
然后設置Android Thread vmThread變量為vmThreadObj。
這樣通過vmThreadObj, Android Thread就和dalvik thread關聯起來了。
然后就是
int cc = pthread_create(&threadHandle, &threadAttr, interpThreadStart, newThread);
Yes,這個就是linux操作系統創建新線程的API接口!
接下來我們分析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); }
首先從Android Thread獲得name,然后通過prepareThread設置線程的一些屬性。並調用setThreadSelf方法,把dalvik thread放入TLS。
然后執行Android Thread的run方法。
public void run() { if (target != null) { target.run(); } }
至此,通過操作系統提供的接口,thread里面的run方法,在新線程中運行起來了!
本文參考:
1.《深入理解android內核設計思想》林學森
2.《Android內核剖析》
3.羅朝輝 http://www.cppblog.com/kesalin/archive/2014/07/11/android_thread_impl.html
相關文章:
android 進程/線程管理(一)----消息機制的框架
android 進程/線程管理(三)----Thread,Looper / HandlerThread / IntentService

