There are two typical usage scenarios for ThreadLocal in common business development.

  • ThreadLocal is used to hold objects that are unique to each thread, creating a copy for each thread so that each thread can modify its own copy without affecting other threads’ copies, ensuring thread-safety.
  • ThreadLocal is used in scenarios where information needs to be kept independently within each thread so that it can be more easily retrieved by other methods. Each thread may get different information. After the previous method holds the information, subsequent methods can get the information directly through ThreadLocal, avoiding passing arguments, similar to the concept of global variables.

ThreadLocal isolates the operations of different threads from each other. So what is the underlying storage structure? First ThreadLocal is Thread dimensions, Thread, ThreadLocal, what is the relationship between ThreadLocalMap?

As shown in figure Thread1, this is a Thread whose arrow points to ThreadLocalMap1. This means that each Thread object holds a member variable of type ThreadLocalMap. The member variable that Thread 1 owns in this case is ThreadLocalMap1.

A ThreadLocalMap itself is like a Map, with key-value pairs. So let’s see what its key and value are. You can see that on the left side of the table are ThreadLocal1, ThreadLocal2… ThreadLocaln, you can see that the key here is a reference to ThreadLocal.

On the right side of the table are values, which is what we want ThreadLocal to store, such as all variable User objects.

A Thread has only one ThreadLocalMap, while a ThreadLocalMap can have many threadLocalizations, each of which corresponds to a value. Since a Thread can call multiple ThreadLocal’s, a Map data structure called ThreadLocalMap is used to store ThreadLocal’s and values.

Using this image, we can understand the macro relationships among threads, ThreadLocal, and ThreadLocalMap.

Source code analysis

Now that we know their relationships, we can do source analysis to get a closer look at their internal implementations.

  • The get method

The source code

public T get(a) {

    // Get the current thread

    Thread t = Thread.currentThread();

    A ThreadLocalMap object is available in each thread

    ThreadLocalMap map = getMap(t);

    if(map ! =null) {

        // Get the Entry object in ThreadLocalMap and get the Value

        ThreadLocalMap.Entry e = map.getEntry(this);

        if(e ! =null) {

            @SuppressWarnings("unchecked")

            T result = (T)e.value;

            returnresult; }}ThreadLocalMap is created if it has not been created before

    return setInitialValue();

}
Copy the code

CurrentThread gets a reference to the currentThread and passes that reference to getMap to get the ThreadLocalMap of the currentThread.

And then an if (map! If (map == null) no ThreadLocalMap has been created in this thread before, so setInitialValue is used to create a ThreadLocalMap. If the map! = null, we should use this reference (that is, the reference of the current ThreadLocal object) to get its corresponding Entry, and then use this Entry to get the value inside, and finally return it as the result.

Note that the ThreadLocalMap is stored in the Thread class, not in a ThreadLocal.

  • GetMap method

The source code

ThreadLocalMap getMap(Thread t) {

    return t.threadLocals;

}
Copy the code

As you can see, this method clearly shows the relationship between Thread and ThreadLocalMap, as ThreadLocalMap is a member variable of the Thread. This method is used to obtain the ThreadLocalMap object of the current thread. Each thread has a ThreadLocalMap object called threadLocals. The initial value of this object is null.

ThreadLocal.ThreadLocalMap threadLocals = null;
Copy the code
  • Set method

The source code

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

The set method is used to store the desired value. As you can see, it still needs to get a reference to the current thread and use that reference to get ThreadLocalMap. Then, if map == null, the map is created, and when map! If = null, the map.set method is used to set the value.

Map.set (this, value) is passed in as a reference to the current ThreadLocal, and its key is of type ThreadLocal. The second argument is the value we passed in, so we can save the key-value pair to ThreadLocalMap.

  • Class ThreadLocalMap, also known as thread.threadlocals

The following snippet of the custom ThreadLocalMap class in ThreadLocal:

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;

/ /...

}
Copy the code

The ThreadLocalMap class is a member variable of the Thread class for each Thread, the most important of which is the Entry inner class in this snippet of code. In ThreadLocalMap there will be an array of entries called table. We can think of Entry as a map whose key-value pairs are:

  • Key, current ThreadLocal;
  • Value, the actual variable that needs to be stored

Conclusion: The relationship between Thread, ThreadLocal, and ThreadLocalMap classes is analyzed. A Thread has a ThreadLocalMap, and the keys of a ThreadLocalMap are ThreadLocal, which are used to store and maintain content.