The Android messaging mechanism Looper uses ThreadLocal to isolate data. Now let’s examine the wave, starting with its set() process.
1. Set (T value) Process analysis
In this case, by calling ThreadLocal’s set method, it’s very simple, with a few simple steps:
- Gets the thread calling this method.
- Gets the ThreadLocalMap and nulls the map.
ThreadLocalMap is similar to a HashMap in that it uses a key-value mapping.
Ii. Get () process analysis
In this case, we get the current thread and ThreadLocalMap, and then judge the map. Let’s start with map empty:
Feel familiar with the set process. In this case, if get does not get elements or the map is empty, it will enter the process. InitialValue () actually returns NULL, that is, if get does not get the element or if the map is empty, the map is created and null is returned.
Let’s look at the process where map is not empty:
The hashcode of the key and the array length -1 are used to obtain the index value of the key, and then the index value is used to obtain the value.
Third, ThreadLocalMap
ThreadLocalMap is a key-value mapping. What are the keys and values? As you can see from the previous analysis, value’s ThreadLocal refers to the generic class, and the key here is actually the ThreadLocal variable.
Each thread has a ThreadLocalMap, where the key corresponds to the ThreadLocal variable and the value corresponds to the object of type T. The set flow is then analyzed.
ThreadLocal’s set method nulls the map, and if the map is empty, it ends up in the following method:
Here, it can be broken down into the following steps:
- Create a table array.
- Get the value of the index, in a way that was described earlier.
- At the location of the index, create a node.
- Set the threshold. Note that this is not 0.75 of the array length, but two-thirds.
Let’s look at the process where map is not empty:
As can be seen from this, after obtaining the index through the key, it will search down the index position until it finds a position where there is no node in the index position. Then, it will create a new node using value in this position, and then it will determine whether to expand the capacity.
As you can see, the set is very simple. If a hash conflict occurs, linear detection is used instead of the linked list + red-black tree data structure used in HashMap.
4. Analysis of memory leakage
Why does ThreadLocal leak? Let’s look at the code for the Entry node in ThreadLocalMap:
It can be seen that this Entry node inherits WeakReference. In the constructor, key is treated with WeakReference, but value is still a strong reference. Now the problem comes. If the key is not strongly referenced by an external object, it will be reclaimed during GC, but its value will not be reclaimed. If the thread that created the ThreadLocal keeps running, the value of the Entry object will not be reclaimed. A memory leak occurs.
The solution is very simple, we need to manually call the remove method.