一:进程和线程的由来 进程是计算机科技发展的过程的产物。 最早计算机发明出来,是为了解决数学计算而发明的。每解决一个问题,就要打纸带,也就是打点。 后来人们发现可以批量的设置命令,由计算机读取这些命令,并挨个执行。 在使用的过程中,有一个问题,如果要做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)
首先通过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./kesalin/archive/2014/07/11/android_thread_impl.html |
|
来自: Library_for_hj > 《Android学习》