The ThreadLocalMap
is a member variable of a Thread
object. It functions as a map to store key-value pairs. The keys in the ThreadLocalMap
are references to ThreadLocal
objects, and the values are objects that the ThreadLocal
is storing, such as user objects.
Each Thread
object contains a single ThreadLocalMap
. The ThreadLocal
objects are associated with their corresponding values in the ThreadLocalMap
. However, it’s important to note that the ThreadLocal
objects themselves are not stored in the ThreadLocalMap
. Instead, they serve as keys to access the corresponding values in the map.
Let’s analyze the source code to further understand the implementation.
The get
method
#
The get
method of ThreadLocal
retrieves the value associated with the ThreadLocal
object. Here is the source code:
public T get() {
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;
return result;
}
}
return setInitialValue();
}
As you can see, the method first obtains a reference to the current Thread
using Thread.currentThread()
. It then calls the getMap
method with this Thread
object to retrieve the corresponding ThreadLocalMap
.
Next, there is an if (map != null)
statement. If the map
is not null, it means that ThreadLocalMap
has been previously created for this thread. In this case, the method retrieves the Entry
from the ThreadLocalMap
using the this
reference (i.e., the reference to the current ThreadLocal
object). It then obtains the value from this Entry
and returns it as the result.
If the map
is null, it means that the ThreadLocalMap
has not been created for this thread. In this case, the setInitialValue
method is called to create and initialize the ThreadLocalMap
.
It’s important to note that the ThreadLocalMap
is stored within the Thread
object, not within the ThreadLocal
object.
The getMap
method
#
Let’s take a look at the getMap
method, which is used by the get
method to retrieve the ThreadLocalMap
from the Thread
object. Here is the source code:
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
The getMap
method simply returns the threadLocals
member variable of the Thread
object. This member variable is where the ThreadLocalMap
is stored.
We can see that this method clearly indicates the relationship between Thread and ThreadLocalMap, showing that ThreadLocalMap is a member variable of the thread. The purpose of this method is to obtain the ThreadLocalMap object within the current thread. Each thread has a ThreadLocalMap object, and the name of this object is threadLocals, with an initial value of null. The code is as follows:
ThreadLocal.ThreadLocalMap threadLocals = null;
The set
method
#
Now let’s take a look at the set
method, its source code is as follows:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
The purpose of the set
method is to save the value we want to store. As can be seen, first, it still needs to obtain the reference of the current thread and use this reference to obtain the ThreadLocalMap. Then, if map == null
, it creates this map, and when map != null
, it uses the map.set
method to set the value.
It can be seen that the two parameters passed in map.set(this, value)
, the first parameter is this
, which refers to the current ThreadLocal, which once again reflects that the key type in ThreadLocalMap is ThreadLocal. The second parameter is the value we passed in, so this key-value pair can be saved in ThreadLocalMap.
ThreadLocalMap class, which is Thread.threadLocals #
Now let’s take a look at the ThreadLocalMap class. The following code excerpt is taken from the ThreadLocalMap class defined in the ThreadLocal class:
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private Entry[] table;
//...
}
The ThreadLocalMap class is a member variable in the Thread class of each thread. The most important part is the Entry inner class extracted from the code. In ThreadLocalMap, there will be an Entry array named table. We can understand Entry as a map, with the key-value pair as follows:
- Key: the current ThreadLocal
- Value: the actual variable that needs to be stored, such as the user object or simpleDateFormat object.
Since ThreadLocalMap is similar to Map, it has a series of standard operations including set, get, rehash, and resize, just like HashMap. However, although the ideas are similar to HashMap, the specific implementation may be slightly different.
For example, one difference is that we know when HashMap encounters hash collisions, it uses chaining (linked list). It first hashes the object into a corresponding cell, and if there is a collision, it chains down in the form of a linked list, as shown in the following image:
But the way ThreadLocalMap handles hash collisions is different. It uses linear probing. If a collision occurs, it does not chain down in the form of a linked list but continues to look for the next empty cell. This is the difference between ThreadLocalMap and HashMap in handling collisions.
The above is the content of this lesson.
In this lesson, we mainly analyzed the relationship between the three very important classes: Thread, ThreadLocal, and ThreadLocalMap. Using diagrams to represent the relationship: each Thread has a ThreadLocalMap, and the key of ThreadLocalMap is ThreadLocal, which is used to store and maintain the content in this way. Afterwards, we analyzed the source code of some important methods for ThreadLocal.