Android Multithreading Analysis II: Thread implementation

Source: Internet
Author: User

Android Multithreading Analysis II: Thread implementation Roche (http://www.cnblogs.com/kesalin/) CC License, reproduced please specify the source

In the previous article, "One of the Android multithreaded analysis: Using thread to download images asynchronously" demonstrates how to use thread to process asynchronous transactions. The Java thread class in the example is a class that is located at the Framework layer itself, and is implemented by the Thread-related method inside the JNI transpose Dalvik. Therefore, to analyze threads in Androd, you need to analyze thread-related code in both layers, which is the subject of this article. This article will refer to the Java thread in the Framework layer as the Android thread/thread, and the thread in Dalvik as the Dalvik thread/thread.

This article refers to the Android source path:
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

First of all to analyze the Android Thread, this class of source code in Android/libcore/luni/src/main/java/java/lang/thread.java, it implements the Runnable interface. Runnable has only one interface for void run () without a parameter return value:

/** * Represents a command that can is 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 was     * Called when a thread was started that had been created with a class which     * Implements {@code Runn Able}.     *    /public void run ();

Android Thread exists in six states, these States are defined in the enumeration state, the source code comments are written very clearly, here is not verbose :

    /**     * A representation of a thread ' s state. A given thread may is in the one     * state at a time.     */Public    enum State {        /**         * The thread had been created, but had 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    }


Some key member variables in the Android Thread class are as follows:

    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: Can be considered as a simple encapsulation of Dalvik thread, the thread class through the Vmthread inside the JNI method to invoke the method of operation thread in Dalvik, through its member variables thread and vmata, we can be Android The thread is associated with the Dalvik thread; group: Each thread belongs to a group, and when the thread is created it joins a specific group, which is removed from the group when the thread is run, daemon: The current thread is not a daemon thread, The daemon thread will run only if no non-daemon thread is running; priority: thread precedence, thread priority for Java thread class is [1, 10], default priority is 5;stacksize: thread stack size, default is 0, that is, using the default thread stack size (determined by the global variable gdvm.stacksize in Dalvik); target: A Runnable object, and the thread's run () method will turn off the target's run () method, which is what the threads actually do with the transaction Id:android thread ID, by incrementing count to get the ID, if it is not displayed to the thread setting name, then use Thread+id as the name of the thread. Note that this is not the real thread ID, that is, the TID printed in Logcat is not the ID, and the TID refers to the id;localvalues of the Dalvik thread: Thread local Storage (TLS) data;

Next, we look at the constructor of the Android Thread, most of the constructors are implemented by the transpose static function create, the following is a detailed analysis of the Create this key function:

    private void Create (Threadgroup group, Runnable Runnable, String threadname, long stackSize) {Thread currentth        Read = 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.inherit        Ablevalues); }//Add ourSelves to We threadgroup of choice this.group.addThread (this); }

First, the current thread in which the creation thread resides is obtained through the static function CurrentThread, and some properties of the current thread are passed to the new thread that is about to be created. This is achieved through the code in the Vmthread transpose Dalvik:

    public static Thread CurrentThread () {        return vmthread.currentthread ();    }

The CurrentThread of Vmthread is a native method whose JNI is implemented as Dalvik_java_lang_ in Android/dalvik/vm/native/java_lang_vmthread.cpp Vmthread_currentthread Method:

static void Dalvik_java_lang_vmthread_currentthread (const u4* args,    jvalue* pResult) {    unused_parameter (args );    Return_ptr (Dvmthreadself ()->threadobj);}

The Dvmthreadself () method in this method is defined in the Android/dalvik/vm/thread.cpp:

thread* dvmthreadself () {    return (thread*) pthread_getspecific (gdvm.pthreadkeyself);}

From the above call stack can be seen, each Dalvik thread will be stored in the key to pthreadkeyself thread local storage, the current thread, only need to base on this key query to obtain, Dalvik thread has a named Threadobj Member variables:

    /* The java/lang/thread that we is associated with */    object*     threadobj;

Dalvik thread This member variable threadobj is associated with the corresponding Android Thread object, so the native method Vmthread.currentthread () returns the current Dalvik stored in TLS The Android thread that corresponds to threads.

Then analyze the code above, if the new thread is not assigned to the group then the group will be specified as the current thread in the group, and then set the new thread name,priority and so on. Finally, the new thread is added to the group by calling the Addthread method of Threadgroup:

    /**     * 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));        }    }

The Threadgroup code is relatively simple, it has a list named Threadrefs, holds a thread reference belonging to the same group, and can perform some threading on a set of threads.

The above analysis is the construction process of the Android thread, from the above analysis can be seen, the Android thread construction method is only set a number of thread properties, and did not really go to create a new Dalvik Thread,dalvik thread The creation process will not take place until the client code calls the Android Thread's Start () method. Let's analyze the start () method of the Java Thread:

Public synchronized void Start () {        if (hasbeenstarted) {            throw new Illegalthreadstateexception ("Thread already Started. "); TODO externalize?        }        Hasbeenstarted = true;        Vmthread.create (this, stackSize);}    }

The Start method of the Android Thread is simple, just the native method of the transpose Vmthread create, whose JNI implementation is Android/dalvik/vm/native/java_lang_vmthread.cpp The Dalvik_java_lang_vmthread_create method:

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 would pin threadobj for us since it is an argument */Dvmcreateinterpthread (threadobj, (int) stack    Size); Return_void ();} Dvmcreateinterpthread implementation in Thread.cpp, because the content of this function is very long, here only the key place: 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 is * still in the "Thread list" but     Thread has not started * Executing user code and therefore have 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;}

First, by calling Allocthread to create a Dalvik thread named Newthread and setting some properties, set its member variable threadobj to the incoming Android thread, so Dalvik thread is associated with an The droid thread is associated; then create a Vmthread object named Vmthreadobj, set its member variable vmdata to Newthread, set the member variable of the Android thread Threadobj Vmthrea D for this vmthreadobj, so that the Android thread is associated with the Dalvik thread through the vmthread member variable vmdata.

Then, create the pthread thread through pthread_create and let this thread start, so that it will go into the thread entry run, and we'll look at the new thread's thread entry method Interpthreadstart, same List only the key places:

/* * 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 US state so the GC would wait for we from now on.     If a GC is * in progress the suspend us.    */Dvmchangestatus (self, thread_running);     /* * Execute the "Run" method. * * At the "Our stack are empty, so somebody who comes looking for * stacks traces right now won ' t has much t  o Look at.     This is normal. */method* Run = self->threadobj->clazz-&Gt;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 was called while executing in the new thread, but before the * thread was added to the thread list. * * Note:the Threadlistlock must is 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); ...}

In the thread entry method Interpthreadstart of the new thread, first set the name of the thread, then set the thread ID and some other properties by calling Preparethread, and call setthreadself to add the new Dalvik thre The ad itself is stored in TLS so that it can be obtained from TLS after the Dvmthreadself method. Then modify the status to Thread_running and call the Run method corresponding to the Android THREAD to run the client code:

    public void Run () {        if (target! = null) {            target.run ();        }    }

For Android Handlerthread, which inherits from Android Thread with Looper, it will call it to overwrite the Run method (): (for the topic of Looper, the next one will say, here's a little bit)

    public void Run () {        Mtid = Process.mytid ();        Looper.prepare ();        Synchronized (this) {            mlooper = Looper.mylooper ();            Notifyall ();        }        Process.setthreadpriority (mpriority);        Onlooperprepared ();        Looper.loop ();        Mtid =-1;    }

The

Target has been described earlier as a place where threads actually handle logical transactions. Once the logical transaction has finished returning from run, the thread goes back to the  interpthreadstart method and continues with the Dvmdetachcurrentthread method:

/* * Detach the thread from the various data structures, notify other threads * that is 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.voffjavalangthreadgrou        P_removethread];        Jvalue unused;    Dvmcallmethod (self, removethread, group, &unused, Self->threadobj);  }/* Clear the Vmthread reference in the Thread object.  Interpreted code * would now see the this Thread was not running. As this is reference to the Vmthread object then the VM knows about, we * has to create a interna     L 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_v    Mdata, NULL);  .../* * Thread.Join () is implemented as a object.wait () on the vmthread * Object.     Signal anyone is waiting.    */Dvmlockobject (self, vmthread);    Dvmobjectnotifyall (self, vmthread);    Dvmunlockobject (self, vmthread);    Dvmreleasetrackedalloc (Vmthread, self);    Vmthread = NULL;    ... dvmlockthreadlist (self);     /* * Lose the JNI context.    */dvmdestroyjnienv (SELF-&GT;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);}

In the Dvmdetachcurrentthread function, first gets the current thread self, which is the new thread that is currently executing thread entry, and then obtains the object's location through its corresponding Android thread object Threadobj Grou P, then remove the Threadobj this Android thread object from the group, then clear the association between Android and the Dalvik thread, and notify the other threads of the join thread; Finally, set the thread state to Thread_zombie , clears the thread value stored in TLS and frees memory by calling Freethread, which ends the thread.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.