“PK creative Spring Festival, I am participating in the” Spring Festival Creative submission contest “, please see: Spring Festival Creative Submission Contest”

How ThreadLocal works

We all know that Android does not allow UI updates from threads other than the main thread (the UI thread), on the one hand, if the UI can be modified, the UI components must be locked, which causes design headaches, and on the other hand, threads can block, resulting in a loss of efficiency. So we usually pass tasks to the main thread using a Handler that handles UI updates. How does this work? We need a special data store class called ThreadLocal

private ThreadLocal<Integer> mIntegerThreadLocal = new ThreadLocal<>();
Copy the code

This data store class stores data based on a specific thread.

public class MainActivity extends AppCompatActivity {
    private ThreadLocal<Integer> mIntegerThreadLocal = new ThreadLocal<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        mIntegerThreadLocal.set(1);
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                mIntegerThreadLocal.set(0);
                Log.d("Thread0".""+mIntegerThreadLocal.get());
            }
        }).start();
        try{
            Thread.sleep(1000);
        }catch (Exception e){
            e.printStackTrace();
        }
        Log.d("mainThread".""+mIntegerThreadLocal.get());
        super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }}Copy the code

The result of the program output aboveYou can see that although the same ThreadLocal exists, different threads do not interact with each other. How does ThreadLocal store data to the corresponding thread?

Within each thread will have a ThreadLocal ThreadLocalMap types of data, called threadLocals

When data needs to be stored in ThreadLocal, it will eventually be stored in threadLocals of the thread. . Then we went to see a ThreadLocal ThreadLocalMap class of concrete structure

An Entry class and an Entry array type can be found in the table, where the Entry class is defined as follows:

static class Entry extends WeakReference<ThreadLocal<? >>{
    /** The value associated with this ThreadLocal. */Object value; Entry(ThreadLocal<? > k, Object v) {super(k); value = v; }}Copy the code

Entry inherits from WeakReference >, which points to a ThreadLocal, which itself stores a value. So at this point we have an idea of the entire stored procedure -> Thread class will be stored in a ThreadLocal. ThreadLocalMap ThreadLocals types of data, ThreadLocals has an Entry in the array of type table, each Entry itself will point us to define the ThreadLocal, and We already know the value storage structure with ThreadLocal, but how does that work? Let’s start with the set method of ThreadLocal >

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if(map ! =null)
        map.set(this, value);
    else
        createMap(t, value);
}
Copy the code

Get the ThreadLocals from the Thread and save the data. Then look at

private void set(ThreadLocal
        key, Object value) {

    // We don't use a fast path as with get() because it is at
    // least as common to use set() to create new entries as
    // it is to replace existing ones, in which case, a fast
    // path would fail more often than not.

    Entry[] tab = table;
    int len = tab.length;
    int i = key.threadLocalHashCode & (len-1);

    for(Entry e = tab[i]; e ! =null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<? > k = e.get();if (k == key) {
            e.value = value;
            return;
        }

        if (k == null) {
            replaceStaleEntry(key, value, i);
            return;
        }
    }

    tab[i] = new Entry(key, value);
    int sz = ++size;
    if(! cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }Copy the code

This process iterates through the table array we mentioned earlier, comparing the ThreadLocal points to the same, and assigning if so. So that’s about it, set, and then get

public T get(a) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if(map ! =null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if(e ! =null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            returnresult; }}return setInitialValue();
}
Copy the code

This process is also very simple, that is, call the ThreadLocal of this method to get the corresponding Entry, and then get the value naturally.

conclusion

As a whole, we defined the ThreadLocal is just a teaser, real data storage place in each thread corresponding ThreadLocal. ThreadLocals ThreadLocalMap type of data, However, it is important to remember that each thread may have more than one ThreadLocal, so we set an Entry type data in the ThreadLocalMap to place data for each ThreadLocal