How the threadlocal of the Android messaging mechanism works

Source: Internet
Author: User

Mention of the message mechanism should not be unfamiliar to everyone, in the daily development of the inevitable to be involved in this aspect of the content. From a development perspective, handler is the upper-level interface of the Android messaging mechanism, which makes it possible to interact with handler only during the development process. The handler process is simple, and it makes it easy to switch a task to the thread where the handler is located. Many people think that handler's role is to update the UI, which is true, but updating the UI is just a special usage scenario for handler, specifically: Sometimes it takes time-consuming IO operations in a sub-thread, which may be reading files or accessing the network, It may be necessary to make some changes to the UI when the time-consuming operation is complete, and because of the limitations of the Android development specification, we are not able to access the UI controls in the main thread, otherwise it will trigger the program exception, which can be done by switching the update UI operation to the main thread by handler. So, essentially, handler isn't dedicated to updating the UI, it's just that it's often used by everyone to update the UI.


Android's message mechanism mainly refers to the handler operating mechanism, handler operation requires the underlying MessageQueue and Looper support. MessageQueue's Chinese translation is Message Queuing, which, as its name implies, stores a set of messages that provide insertions and deletions in the form of queues, even though they are called message queues, but their internal storage structure is not a real queue, but rather a single-linked list of data structures to store the message lists. Looper's Chinese translation is a loop, which can be understood here as a message loop, because MessageQueue is just a memory unit of the message, it cannot process the message, and Looper fills this function, Looper will look in the form of infinite loops to find out if there are any new messages. If you have something to do with the message, otherwise you will always wait. There is a special concept in Looper that threadlocal,threadlocal is not a thread, but that it can store data in each thread. As you know, handler is created with the current thread's looper to construct the message circulatory system, so how does handler internally get Looper to the current thread? This is going to use threadlocal, threadlocal can store and provide data between different threads, and the looper of each thread can be easily obtained through threadlocal. Note, of course, that threads are not looper by default, and you must create looper for threads if you need to use handler. The main thread, also called the UI thread, that is often mentioned, is that Activitythread,activitythread is initialized when it is created, which is why the handler is used by default in the main thread.


Threadlocal is a data storage class inside a thread that can store data in a specified thread, and after the data is stored, only the stored data can be obtained in the specified thread, and the data cannot be obtained for other threads. The use of threadlocal in daily development is less, but in some special scenarios, it is easy to implement some seemingly complex functions through threadlocal, which is also reflected in the Android source code, such as Looper, Threadlocal is used in both Activitythread and AMS. Specific to the threadlocal of the use of the scene, this is not a unified description, in general, when some data is a thread-scoped and different threads have different copies of the data, you can consider the use of threadlocal. For example, for handler, it needs to get the current thread of looper, it is obvious that the scope of Looper is the thread and different threads have different looper, this time through the threadlocal can easily achieve looper in-thread access, If threadlocal is not used, then the system must provide a global hash table for handler to find the looper of the specified thread, so that a class similar to Loopermanager must be provided. But the system did not do so, but chose Threadlocal, which is the benefit of threadlocal.


Threadlocal Another usage scenario is object delivery in complex logic, such as listener delivery, sometimes the task in a thread is too complex, which may appear to be a deeper function call stack and a multiplicity of code portals, in which case we need the listener to run through the entire thread. What can we do at this time? In fact, you can use the threadlocal, using threadlocal can let the listener as a global object within the thread, as long as the internal threads through the Get method can get to the listener. And if you don't use threadlocal, then we can think of the following two ways: The first method is to pass the listener as a parameter in the function call stack, the second method is to use the listener as a static variable for thread access. Both of these methods are limited. The problem with the first method is that when the function call stack is deep, passing the listener object through the function arguments is almost unacceptable, which makes the design of the program look bad. The second method is acceptable, but the state is not extensible, such as if there are two threads executing at the same time, then you need to provide two static listener objects, if 10 threads are executing concurrently? 10 Static listener objects available? This is obviously inconceivable, and the use of threadlocal each listener object is stored inside its own thread, according to which there will be no problem with Method 2.

The introduction of so many threadlocal knowledge, may still be a little abstract, the following through the actual example for you to demonstrate the true meaning of threadlocal. First define a Threadlocal object, where the Boolean type is selected, as follows:

Private threadlocal<boolean>mbooleanthreadlocal = new threadlocal<boolean> ();

It then sets and accesses its value in the main thread, child thread 1, and child thread 2, as shown in the following code:

Mbooleanthreadlocal.set (TRUE); LOG.D (TAG, "[thread#main]mbooleanthreadlocal=" + mbooleanthreadlocal.get ()); New Thread ("Thread#1") {@Overridepublic void Run () {Mbooleanthreadlocal.set (false); LOG.D (TAG, "[thread#1]mbooleanthreadlocal=" + mbooleanthreadlocal.get ());};}. Start (), New Thread ("Thread#2") {@Overridepublic void run () {LOG.D (TAG, "[thread#2]mbooleanthreadlocal=" + Mbooleanthreadlocal.get ());};}. Start ();

In the preceding code, set the value of Mbooleanthreadlocal to true in the main thread, set the value of Mbooleanthreadlocal to false in child thread 1, and do not set the value of mbooleanthreadlocal in child thread 2. then respectively in 3 threads through the Get method to mbooleanthreadlocal value, according to the description of the front face threadlocal, this time, the main thread should be true, child thread 1 should be false, and child thread 2 because there is no value set, So it should be null, install and run the program, the logs are as follows:

D/testactivity (8676): [Thread#main]mbooleanthreadlocal=true

D/testactivity (8676): [Thread#1]mbooleanthreadlocal=false

D/testactivity (8676): [Thread#2]mbooleanthreadlocal=null

As can be seen from the above log, although the same Threadlocal object is accessed in different threads, the value they get by threadlocal is not the same, which is the magic of threadlocal. Combining this example and then looking at the theoretical analysis of the two use scenarios of threadlocal, we should be able to better understand the use of threadlocal. Threadlocal has this wonderful effect because different threads access the same threadlocal get method, and threadlocal internally takes an array from the respective thread. Then from the array according to the current threadlocal index to find the corresponding value value, it is clear that the different threads in the array is different, this is why through the threadlocal can be in different threads to maintain a copy of a set of data and do not interfere with each other.

After an introduction to the use of ThreadLocal and the working process, the following analysis of the internal implementation of ThreadLocal, ThreadLocal is a generic class, which is defined as public class Threadlocal<t> Just figure out the threadlocal get and set method to understand how it works.

First look at the set method of Threadlocal, as shown below:

public void Set (T value) {Thread CurrentThread = Thread.CurrentThread (); Values values = VALUES (CurrentThread), if (values = = null) {values = Initializevalues (CurrentThread);} Values.put (this, value);}

        in the above set method, the Threadlocal data in the current thread is first obtained through the values method, if it is obtained? In fact the way to get is also very simple, in the thread class content there is a member dedicated to storing the thread's ThreadLocal data, as follows: Threadlocal.values Localvalues, Therefore, getting the threadlocal data for the current thread becomes surprisingly simple. If the value of localvalues is null, then it needs to be initialized, and the value of threadlocal is initialized before it is stored. Let's see how the value of threadlocal is stored in the localvalues. There is an array inside Localvalues: The value of private object[] table,threadlocal is present in the table array, Here's how Localvalues uses the Put method to store the value of threadlocal in a table array, as follows:

void put (threadlocal<?> key, Object value) {cleanUp ();//Keep track of first Tombstone. That's where we want to go back//and add an entry if necessary.int Firsttombstone = -1;for (int index = Key.hash & MA SK;; 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;}}} 

The above code implements the stored procedure of the data and does not analyze its specific algorithm here, but we can draw a storage rule, That's the value of threadlocal. The stored position in the table array is always the next position of the object identified by the reference field of threadlocal. For example, Threadlocal's Reference object is indexed in the table array, so the index of the Threadlocal value in the table array is index+1. The value of the final threadlocal will be stored in the table array: Table[index + 1] = value.

The set method of Threadlocal is analyzed, and the Get method is analyzed here, as follows:

Public T Get () {//-Optimized for the fast path. Thread CurrentThread = Thread.CurrentThread (); Values values = VALUES (CurrentThread), if (values = null) {object[] table = Values.table;int index = hash & Values.mas K;if (This.reference = = Table[index]) {return (T) Table[index + 1];}} else {values = Initializevalues (CurrentThread);} Return (T) Values.getaftermiss (this);}

It can be found that the logic of the Get method of threadlocal is also clear, it is also to take out the current thread of the Localvalues object, if the object is NULL then return the initial value, the initial value is described by the InitialValue method of Threadlocal, By default it is null, and of course you can override this method, and its default implementation is as follows:

/** * Provides the initial value of this variable for the current thread. * The default implementation returns {@code null}. * * @return The initial value of the variable. */protected T InitialValue () {return null;}

If the Localvalues object is not NULL, then take out its table array and find out the position of the Threadlocal Reference object in the table array, The data stored in the next position in the table array is then the value of threadlocal.

As can be seen from the set and get methods of threadlocal, the objects they manipulate are table arrays of the Localvalues objects of the current thread, so the set and get methods of the same threadlocal are accessed in different threads. Their read and write operations to Threadlocal are limited to the internals of their respective threads, which is why threadlocal can store and modify data across multiple threads, understanding how threadlocal is implemented to help understand how Looper works.

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

How the threadlocal of the Android messaging mechanism works

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.