Android multithreading Analysis 2: Implementation of Thread, androidthread

Source: Internet
Author: User

Android multithreading Analysis 2: Implementation of Thread, androidthread
Android multi-Thread Analysis II: Thread implementation Luo chaohui (http://www.cnblogs.com/kesalin/) CC license, reproduced please indicate the source

In the previous article "Android multi-Thread analysis: Using Thread to asynchronously download images", we demonstrated how to use Thread to process asynchronous transactions. In this example, the Java Thread class is located at the Framework layer, and is implemented through the Thread-related methods in dalvik through JNI redirection. Therefore, to analyze the threads in Androd, we need to analyze the Code related to the threads in these two layers. This is the topic of this article. In this article, Java Thread in the Framework layer is called Android Thread/Thread, and the Thread in dalvik is called dalvik Thread/Thread.

The Android source code path involved in this article:
Android/libcore/luni/src/main/java/lang/Runnable. java
Android/libcore/luni/src/main/java/lang/Thread. java
Android/libcore/luni/src/main/java/lang/ThreadGroup. java
Android/libcore/luni/src/main/java/lang/VMThread. java
Android/dalvik/vm/native/java_lang_VMThread.cpp
Android/dalvik/vm/Thread. cpp

First, we will analyze the Android Thread. The source code of this class is in android/libcore/luni/src/main/java/lang/Thread. java, which implements the Runnable interface. Runnable only has one void run () interface without any parameters and no return value:

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

The Android Thread has six States. These States are defined in the enumeration State, and the source code annotations are clearly written. Here we will not go down:

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


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: it can be considered as a simple encapsulation of dalvik thread. The Thread class uses the JNI method in VMThread to call the method used to operate the thread in dalvik, through its member variables thread and vmata, we can associate the Android Thread with the dalvik Thread. group: Each Thread belongs to a group. When a Thread is created, a specific group is added. When the Thread stops running, will be removed from this group; daemon: whether the current thread is a daemon thread. The daemon thread runs only when no non-daemon thread is running; priority: thread priority, the Thread priority of the Java Thread class ranges from 1 to 10. The default priority is 5. stackSize: the Thread stack size. The default value is 0, that is, the default thread stack size is used (by the global variable gDvm in dalvik. stackSize); target: a Run Nable object. The run () method of the target will be converted in the run () method of the Thread, which is the place where the Thread actually processes transactions; id: Android Thread id, this id is obtained through incremental count. If the Thread name is not displayed, the Thread + id is used as the Thread name. Note that this is not the real thread id, that is, the tid printed in logcat is not the id, that is, the tid is the id of the dalvik thread; localValues: local thread storage (TLS) data;

Next, let's take a look at the Android Thread constructor. Most constructor functions are implemented through the transpose static function create. The following describes the key function 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);    }

First, obtain the current thread of the Creation thread through the static function currentThread, and pass some attributes of the current thread to the new thread to be created. This is achieved through VMThread to call the code in dalvik:

    public static Thread currentThread() {        return VMThread.currentThread();    }

The currentThread of VMThread is a native method, and its JNI is implemented as the Dalvik_java_lang_VMThread_currentThread method in 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);}

The dvmThreadSelf () method in this method is defined in android/dalvik/vm/Thread. cpp:

Thread* dvmThreadSelf(){    return (Thread*) pthread_getspecific(gDvm.pthreadKeySelf);}

From the preceding call stack, we can see that each dalvik thread stores itself in the local storage of the thread whose key is pthreadKeySelf. When obtaining the current thread, you only need to query and obtain it based on this key, dalvik Thread has a member variable named threadObj:

    /* the java/lang/Thread that we are associated with */    Object*     threadObj;

The threadObj member variable dalvik Thread is associated with the corresponding Android Thread object. Therefore, the native method VMThread. currentThread () returns the Android Thread corresponding to the current dalvik Thread stored in TLS.

Next, analyze the code above. If no group is specified for the new thread, the group will be specified as the group where the current thread is located, and then name and priority will be set for the new thread. Finally, add the new thread 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 Code of ThreadGroup is relatively simple. It has a list named threadRefs, which holds the thread references of the same group and can perform some thread operations on a group of threads.

The above analysis is the construction process of the Android Thread. From the above analysis, we can see that the Android Thread construction method only sets some Thread attributes and does not actually create a new dalvik Thread, the creation process of dalvik Thread will not be performed until the client code calls the start () method of Android Thread. Next we will analyze the start () method of 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 Android Thread is very simple. It is just to call the native method create of VMThread. Its JNI is implemented as the Dalvik_java_lang_VMThread_create method in android/dalvik/vm/native/java_lang_VMThread.cpp:

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 ();} Implementation of dvmCreateInterpThread in Thread. in cpp, because the content of this function is very long, only the key points are listed here: 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 wowould 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 ;}

First, call allocThread to create a dalvik Thread named newThread and set some attributes. Then, set its member variable threadObj to the imported Android Thread, so that the dalvik Thread is associated with the Android Thread; create a VMThread object named vmThreadObj, set its member variable vmData to newThread, and set the member variable vmThread of Android Thread threadObj to vmThreadObj, in this way, the Android Thread is associated with the dalvik Thread through the VMThread member variable vmData.

Then, create a pthread through pthread_create and start the thread. This will enter the thread entry of the thread to run. Let's take a look at the thread entry method interpThreadStart of the new thread, similarly, only key points are listed:

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

In the thread entry method interpThreadStart of the new thread, first set the thread name, and then set the thread id and other attributes by calling prepareThread, call setThreadSelf to save the new dalvik Thread to TLS, so that it can be obtained from TLS through the dvmThreadSelf method. Then, change the status to THREAD_RUNNING, call the run method of the corresponding Android Thread, and run the Customer Code:

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

For Android HandlerThread inherited from Android Thread with logoff, it will be called to overwrite the run method (): (the next topic about logoff will be mentioned here for the time being)

    public void run() {        mTid = Process.myTid();        Looper.prepare();        synchronized (this) {            mLooper = Looper.myLooper();            notifyAll();        }        Process.setThreadPriority(mPriority);        onLooperPrepared();        Looper.loop();        mTid = -1;    }

Target has been introduced earlier. It is the place where the thread actually processes logical transactions. Once the logical transaction is processed and returned from run, the thread will return to the interpThreadStart method and continue to execute the dvmDetachCurrentThread method:

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

In the dvmDetachCurrentThread function, first obtain the current thread self, which is the new Thread that currently executes the thread entry, and then obtain the group of the object through its corresponding Android Thread object threadObj, then, remove the Android Thread threadObj object from the group. Then, clear the association between Android and dalvik threads and notify other threads that join the Thread. Finally, set the Thread status to THREAD_ZOMBIE, the thread value stored in TLS is cleared and the memory is released by calling freeThread. This ends the thread.

 


How does the Thread subclass implement the multithreading mechanism?

Let's talk about the mechanism of implementing multithreading in java:
Two Methods: Inherit the Thread class, and rewrite the run () method of the parent class, and implement the Runnable interface, which is also the run () method. The run () method is very important. It is the core of the runtime when you create a new thread. Note that you should not call the run () method yourself. If you call the run () method by yourself, it's just that you write the line of calling code. The thread that runs the line of code is executing this method, rather than creating a new thread for execution. This is also often confusing in my previous multi-threaded programming.
Speaking of this, how to create a thread? Simple: Thread newThread = new Thread (parameter); Parameters in the constructor are an instance of the previous two implementation classes. So when you call: newThread. after the start () method, a new thread is started. When the thread executes run (), that is, the run () method of the instance in the parameter is the main body of the thread execution.
Note: The main run () method executed by a thread does not need to be displayed and called.

Implement a multi-threaded program by inheriting the Thread class. The program starts three

This morning, I suddenly thought of another idea!
The Code is as follows:
# Include <iostream. h>
# Include <afxmt. h>
HANDLE h1, h2, h3;
Dword winapi ThreadProc1 (LPVOID lpParameter );
Dword winapi ThreadProc2 (LPVOID lpParameter );
Dword winapi ThreadProc3 (LPVOID lpParameter );

Dword winapi ThreadProc1 (LPVOID lpParameter)
{

Cout <"ThreadProc1" <endl;

Return 0;

}
Dword winapi ThreadProc2 (LPVOID lpParameter)
{

Cout <"ThreadProc2" <endl;

Return 0;

}
Dword winapi ThreadProc3 (LPVOID lpParameter)
{

Cout <"ThreadProc3" <endl;

Return 0;

}

Void main ()
{

H1 = CreateThread (NULL, 0, ThreadProc1, NULL, create_suincluded, NULL );
H2 = CreateThread (NULL, 0, ThreadProc2, NULL, create_suincluded, NULL );
H3 = CreateThread (NULL, 0, ThreadProc3, NULL, create_suincluded, NULL );
// SetThreadPriority (h, THREAD_PRIORITY_NORMAL );
// SuspendThread (h );
ResumeThread (h1 );
Sleep (10 );
ResumeThread (h2 );
Sleep (10 );
ResumeThread (h3 );
Sleep (10 );
Cout <"end" <endl;
}

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.