• notice
  • Congratulations on the launch of the Sought Tech site

ThreadLocal, Thread and ThreadLocalMap share


The usefulness of ThreadLocal

ThreadLocal is to record a copy of the data to a thread to ensure the thread safety of the data

For example, the Connection of the database is put into ThreadLocal, a transaction will use a lot of DAO, but only a common Connection can be used, so as to ensure the integrity of the transaction

So when one of the variables of a certain class will be used multiple times by the same thread, and it is strictly stipulated that this variable must be operated every time

Then you can put this variable into ThreadLocal

Spring also puts various beans into ThreadLocal to ensure the "stateless" of beans

Don't be misled

Today I read the introduction about ThreadLocal, and some blogs about ThreadLocal on the Internet. This principle introduction is really a pit, a big mistake

You may have seen the following simple implementation ideas of the so-called ThreadLocal:

After that, I added:

Although the ThreadLocal implementation version in the above code listing is relatively simple and crude, its purpose is mainly to present the implementation ideas of the ThreadLocal class provided in the JDK

The above simplified ThreadLocal implementation is fundamentally wrong.

Not only in some blogs, but also in books. Spreading knowledge to others can indeed simplify the code implementation, but it does not mean that the correct implementation ideas have been changed!

This will mislead others to further study ThreadLocal

The real implementation of ThreadLocal

Let’s talk about the summary first and compare it with the above mistakes

1. ThreadLocalMap Don't look at the end of a Map, in fact, it is a reimplemented class

   It has nothing to do with Map. If the Map interface is not implemented, HashMap is useless. Don't think that you can only use map to find the value according to the key.

2. The thread finds the corresponding value according to the key. This key is not the thread id, but the ThreadLocal class

   Why, because ThreadLocalMap is stored in threads, each thread has only one ThreadLocalMap that belongs to itself

   In this case, what's the point of saving a hairy thread id?

Uncover the real relationship between Thread, ThreadLocal, ThreadLocalMap

First enter ThreadLocal and find the following

 ThreadLocalMap is actually implemented in ThreadLocal

 Find the set() method of ThreadLocal directly

copy code

1      public  void set(T value) { 2          Thread t = Thread.currentThread();   // Get the current thread 3          ThreadLocalMap map = getMap(t);    // Pass the current thread as a parameter to get ThreadLocalMap 4          if (map != null ) 5              map.set( this , value); 6          else 7              createMap(t, value); 8      }

copy code


Then enter the getMap() method

1      ThreadLocalMap getMap(Thread t) { 2          return t.threadLocals;         // After tracing, we found that t.threadLocals is ThreadLocal.ThreadLocalMap threadLocals; 3      }


If the obtained map is null, it means it is the first time, go to createMap method to create

1   void createMap(Thread t, T firstValue) { 2          t.threadLocals = new ThreadLocalMap( this , firstValue);   // See, ThreadLocalMap is directly saved for Thread3      }


Enter the new ThreadLocalMap method, note here that the incoming this refers to ThreadLocal


copy code

1   ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {    // See the parameter name, firstKey, ThreadLocal is passed in as the key value! 2              table = new Entry[INITIAL_CAPACITY];                 // table is actually private Entry[] table; just an array 3              int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1 ); 4              table[i] = new Entry(firstKey, firstValue) ; 5              size = 1 ; 6              setThreshold(INITIAL_CAPACITY); 7          }

copy code




ThreadLocalMap does not implement the Map interface and has nothing to do with Map. As for what Entry is, let's see

copy code

1  static  class Entry extends WeakReference<ThreadLocal<?>> { 2              /** The value associated with this ThreadLocal. */ 3              Object value; 4  5              Entry(ThreadLocal<?> k, Object v) { 6                  super (k); 7                  value = v; 8              } 9          }

copy code

First of all, WeakReference refers to the meaning of weak reference. Inheriting this thing has the following effects:

When an object is only pointed by weak reference (weak reference) without any other strong reference (strong reference), if the GC runs at this time, then the object will be reclaimed, regardless of whether the current memory space is enough, this Objects are recycled.

The advantage is that if a ThreadLocal is recycled, the key of ThreadLocalMap will also be recycled in the next GC() (otherwise it will cause memory leak, and the key will never be called)


Entry是一个ThreadLocalMap的内部类,跟Map的Entry实现有点像,有key和value的定义(俗称 桶)



copy code

1     private  void set(ThreadLocal<?> key, Object value) { 2  3              Entry[] tab = table; 4              int len = tab.length; 5              int i = key.threadLocalHashCode & (len-1 ); 6  7              for ( Entry e = tab[i]; 8                   e != null ; 9                   e = tab[i = nextIndex(i, len)]) { 10                  ThreadLocal<?> k = e.get(); 11  12                  if (k == key) { 13                     e.value = value; 14                      return ; 15                  } 16  17                  if (k == null ) { 18                      replaceStaleEntry(key, value, i); 19                      return ; 20                  } 21              } 22  23              tab[i] = new Entry(key, value); 24              int sz = ++ size; 25              if (!cleanSomeSlots(i, sz) && sz >= threshold) 26                  rehash(); 27          }

copy code

Seeing that there is no for in line 7, directly traverse the Entry array just mentioned, take out the ThreadLocal for comparison (equivalent to key comparison), set the value if it matches, and save it without this key

Why ThreadLocalMap does not use HashMap but implements its own array

The concept of key and value appears, and it is not necessary to use HashMap, why use an array

Personally, I think it saves overhead, the overhead of creating Map objects and the overhead of using Map. After all, the initial default length of ThreadLocalMap is 16, and in reality, a thread will not have such local variables to save


Therefore, when using ThreadLocal to store, ThreadLocal will create a ThreadLocalMap for the thread that calls it, and save it as the key value.

When taking the value, ThreadLocal takes the ThreadLocal saved in Thread, and then uses itself as the key value to take the value

Why is the code of ThreadLocalMap not placed in Thread

There is an answer on the Internet that I think is very reasonable:

It seems more logical to define ThreadLocalMap inside the Thread classBut ThreadLocalMap does not require a Thread object to operate, so defining it in the Thread class will only add some unnecessary overhead.The reason it is defined in the ThreadLocal class is that the ThreadLocal class is responsible for the creation and use of ThreadLocalMapIn general, ThreadLocalMap is not a necessity, the definition in Thread increases the cost, and the definition is created on demand in ThreadLocal.

Threads may not all use ThreadLocal. If they are not used, they will not be assigned a ThreadLocalMap.

In other words, this is actually a good design pattern:

A tool class regards itself as a unique identifier, and to operate the method of the tool class itself, it only needs to record the data to the class that calls it.

ThreadLocal memory leak problem

Normally, we create a thread, which will be destroyed after running, and automatically call the remove() method of ThreadLocal to clear the contents of ThreadLocalMap

However, in practice, we use the thread pool, and the thread will return to the thread pool after running, and will not be destroyed

At this time, the content of ThreadLocalMap is still there (the memory is leaked here)

Therefore, when using ThreadLocal in the thread pool, remember to use the remove() method to clear the key in ThreadLocalMap when run() is finished.


Technical otaku

Sought technology together

Related Topic


Leave a Reply