<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Android多線程分析之二:Thread的實現

      Android多線程分析之二:Thread的實現

      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 類中一些關鍵成員變量如下:

          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:Android 線程 id,通過遞增 count 得到該 id,如果沒有顯示給線程設置名字,那么就會使用 Thread+id 當作線程的名字。注意這不是真正意義上的線程 id,即在 logcat 中打印的 tid 并不是這個 id,那 tid 是指 dalvik 線程的 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);
          }

      首先,通過靜態函數 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 釋放內存,至此線程就終結了。

       

      posted @ 2014-07-10 17:44  飄飄白云  閱讀(4497)  評論(0)    收藏  舉報
      本博客遵循 Creative Commons License “署名-非商業用途-保持一致”創作共用協議。 與我聯系
      主站蜘蛛池模板: 国产极品粉嫩学生一线天| av色蜜桃一区二区三区| 久久丁香五月天综合网| 在线观看人成视频免费| 在线中文字幕第一页| 中文字幕av一区二区| 国产一区二区三区乱码在线观看| 亚洲一区二区偷拍精品| 国产偷人爽久久久久久老妇app| 黄又色又污又爽又高潮| 国产视频深夜在线观看| 熟女少妇精品一区二区| 国产精品亚洲二区亚瑟| 99久久免费精品国产色| 亚洲精品喷潮一区二区三区| 91蜜臀国产自产在线观看| 久久精品蜜芽亚洲国产av| yw尤物av无码国产在线观看| 欧美综合自拍亚洲综合图| 国产精品中文字幕第一区| 中文字幕有码日韩精品| 麻豆精品一区二区三区蜜臀| 亚洲av无一区二区三区| 色综合天天综合天天更新| 久久精品国产88精品久久| 国产成人无码AV片在线观看不卡| 日韩人妻无码一区二区三区| 国产精品99一区二区三区| av在线播放观看国产| 国产精品免费中文字幕| 国产亚洲精品久久综合阿香| 九九热视频在线播放| 亚洲女同精品久久女同| 99国内精品久久久久久久| 韩国三级网一区二区三区| 国产女人18毛片水真多1| 永久免费AV无码国产网站| 亚洲国语自产一区第二页| 精品久久精品午夜精品久久| 国产精品小仙女自拍视频| 国产jizzjizz视频|