转载

android 进程/线程管理(二)----关于线程的迷思

一:进程和线程的由来

进程是计算机科技发展的过程的产物。

最早计算机发明出来,是为了解决数学计算而发明的。每解决一个问题,就要打纸带,也就是打点。

后来人们发现可以批量的设置命令,由计算机读取这些命令,并挨个执行。

在使用的过程中,有一个问题,如果要做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接口。

android 进程/线程管理(二)----关于线程的迷思
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 进程/线程管理(二)----关于线程的迷思

runnable什么也没有,就是run函数。

所以线程的根本就是 创建一个新的线程,运行run方法。

下面我们看看创建线程的过程。

android 进程/线程管理(二)----关于线程的迷思
public Thread() {         create(null, null, null, 0);     }      public Thread(Runnable runnable) {         create(null, runnable, null, 0);     }
android 进程/线程管理(二)----关于线程的迷思

如上所示,常见的应用中使用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();
android 进程/线程管理(二)----关于线程的迷思

Thread* newThread = allocThread(stackSize);
newThread->threadObj = threadObj;
android 进程/线程管理(二)----关于线程的迷思

Object* vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_DEFAULT);
dvmSetFieldInt(vmThreadObj, gDvm.offJavaLangVMThread_vmData, (u4)newThread);
dvmSetFieldObject(threadObj, gDvm.offJavaLangThread_vmThread, vmThreadObj);
android 进程/线程管理(二)----关于线程的迷思

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();
android 进程/线程管理(二)----关于线程的迷思

}

/*
* 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));
android 进程/线程管理(二)----关于线程的迷思

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

正文到此结束
Loading...