How does Android guarantee that a thread can have a maximum of only one looper?

Source: Internet
Author: User

1. How do I create a looper?

The Looper method is private, so it cannot be created directly using its construction method.

privateLooper(boolean quitAllowed) {    new MessageQueue(quitAllowed);    mThread = Thread.currentThread();}

You want to create looper on the current thread. Use Looper's Prepare method, Looper.prepare ().
Suppose we want to implement Looper.prepare () This way now, what do we do? We know that a thread in Android can have at most only one Looper, and if calling Looper.prepare () in a thread that already has Looper, it throws RuntimeException ("Only one Looper might be created Per thread ").

In the face of this demand, we might consider using a hashmap, where key is the thread Id,value for thread-associated looper, plus some synchronization mechanisms to implement Looper.prepare () this way, code such as the following:

 Public classLooper {StaticFinal Hashmap<long, looper> looperregistry =NewHashmap<long, looper> ();Private Static void Prepare() {synchronized (Looper.class) {LongCurrentthreadid = Thread.CurrentThread (). GetId (); Looper L = looperregistry.Get(Currentthreadid);if(L! =NULL)Throw NewRuntimeException ("One Looper may be created per thread"); Looperregistry.put (Currentthreadid,NewLooper (true)); }    }    ...}

The above method locking the Looper.class object. These locking overhead can cause performance bottlenecks.
Is there a better way to implement the Looper.prepare () method? Take a look at the source code of Looper in Android.

 Public classLooper {StaticFinal threadlocal<looper> sthreadlocal =NewThreadlocal<looper> (); Public Static void Prepare() {Prepare (true); }Private Static void Prepare(Boolean quitallowed) {if(sthreadlocal.Get() !=NULL) {Throw NewRuntimeException ("One Looper may be created per thread"); } sthreadlocal.Set(NewLooper (quitallowed)); }    ...}

The Get and set methods of threadlocal are called in the Prepare () method. However, the whole process does not join the sync lock, how does looper implement thread-safe?

2. ThreadLocal

Threadlocal is located in the Java.lang package, and the following is a description of the class in the JDK document

Implements a thread-local storage, that's, a variable for which each thread have its own value. All threads share the same ThreadLocal object, but each sees a different value when accessing it, and changes made by one The thread does not affect the other threads. The implementation supports NULL values.

In general, threadlocal implements thread-local storage.

All threads share the same Threadlocal object, but different threads can only access values associated with their line threads. A thread churn Threadlocal object has no effect on other threads.

Threadlocal provides a new idea for writing multi-threaded concurrent programs. For example, as seen, we were able to understand threadlocal as a piece of storage, cutting this chunk of storage into chunks of small storage areas. Each thread owns a piece of its own store, and its own store operation does not affect other threads. For Threadlocal<looper>, the Looper associated with a particular thread is saved in each small block of storage.


3. Threadlocal's internal implementation principle3.1 The relationship of Thread, threadlocal, and values

The member variable localvalues of thread is representative of the threading-specific variable, and the type is threadlocal.values. Because thread-specific variables can be multiple, and the type is indeterminate, threadlocal.values has a table member variable with type Object array. This localvalues can be understood as a column in a two-dimensional storage area that is related to a particular thread.
The Threadlocal class is equivalent to a proxy. The actual operation of the thread-specific store table is its inner class values.

3.2 Set method
publicvoidsetvalue) {    Thread currentThread = Thread.currentThread();    Values values = values(currentThread);    ifnull) {        values = initializeValues(currentThread);    }    values.put(thisvalue);}Values values(Thread current) {    return current.localValues;}

Since it is related to a particular thread, the current thread is fetched first, and then the current thread-specific storage, the localvalues in thread, is empty if localvalues. Then create one and finally put value in values.

voidPut (threadlocal<?> key, Object value) {cleanUp ();//Keep track of first Tombstone. That's where we want to go back    //and add an entry if necessary.    intFirsttombstone =-1; for(int Index= Key.hash & mask;Index= Next (Index) {Object k = table[Index];if(k = = key.reference) {//Replace existing entry.table[Index+1] = value;return; }if(k = =NULL) {if(Firsttombstone = =-1) {//Fill in null slot.table[Index] = key.reference; table[Index+1] = value; size++;return; }//Go back and replace first tombstone.Table[firsttombstone] = key.reference; Table[firsttombstone +1] = value;            tombstones--; size++;return; }//Remember first tombstone.        if(Firsttombstone = =-1&& k = = TOMBSTONE) {Firsttombstone =Index; }    }}

From the Put method, the threadlocal's reference and values are stored in the table, indexed by index and index+1, respectively.
For the example of Looper,
Table[index] = sthreadlocal.reference; (a weak reference to yourself)
Table[index + 1] = Looper associated with the current thread.

3.3 Get method
Public T get () {//Optimized forThe fast path.    Thread CurrentThread = Thread.CurrentThread (); ValuesValues=Values(CurrentThread);if(Values! = null) {object[] table =Values. Table;int Index= Hash &Values. Mask;if(This.reference = = table[Index]) {return(T) table[Index+1]; }    }Else{Values= Initializevalues (CurrentThread); }returnTValues. Getaftermiss (this);}

First remove the values associated with the thread, and then look in the table for the position of the Threadlocal Reference object in the table. It then returns the object stored in the next location. That is, the value of threadlocal, in the Looper example, is the Looper object associated with the current thread.

As can be seen from the set and get methods, it operates on the table array in the localvalues of the current thread. So different threads call the same Threadlocal object's set and get methods, which means that threadlocal provides a new idea to solve the concurrency problem of multi-thread.

4. Threadlocal behind the design idea thread-specific storage mode

Thread-specific storage allows multiple threads to use the same "logical global" access point to get thread-local objects. Avoids the lock-in cost of each interview object.

The origin of 4.1 thread-specific storage pattern

The errno mechanism is widely used in some operating system platforms.

Errno is the last error code for the recording system. For single threaded threads. Implementing errno in the global scope works fine, but in multithreaded operating systems, multithreaded concurrency can cause a thread to set the errno value to be misinterpreted by other threads.

At the time, very many legacy libraries and applications were written on a single thread, in order to not change existing interfaces and legacy code. Solve the problem of multi-threaded interview errno, Thread-specific storage model was born.

The overall structure of the 4.2 thread-specific storage model

thread-specific objects , equivalent to Looper.
The set of thread-specific objects includes a set of thread-specific objects associated with a particular line threads.

Each thread has its own set of thread-specific objects.

Equivalent to Threadlocal.values.

The set of thread-specific objects can store internal or external threads. Win32, Pthread, and Java all support thread-specific data, which can be stored within threads.
thread-specific object proxies, which allow client to access thread-specific objects like regular objects. Assuming there is no proxy, the client must directly access the thread-specific set of objects and use the keys in the display.

Equivalent to threadlocal<looper>.

Conceptually speaking. The structure of the thread-specific storage can be treated as a two-dimensional matrix, with each key corresponding to a row. Each thread corresponds to a column. The matrix element of the K-line and T-column is a pointer to the corresponding thread-specific object. The thread-specific object agent and the thread-specific set of objects work together to provide the application thread with a security mechanism to access the K-line, T-Column objects.

Attention. This model is just an analogy. In fact, the implementation of the Thread-specific storage pattern does not use a two-dimensional matrix, because the key is not necessarily an adjacent integer.

References
    1. Thread-local Storage
    2. Schema-Oriented Software architecture • Volume 2: Concurrent and networked object modes

How does Android guarantee that a thread can have a maximum of only one looper?

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.