Welcome to Star: github.com/yehongzhi/l…

What is a ThreadLocal

ThreadLocal provides a thread’s local variable, which differs from ordinary variables in that each thread accessing it has its own, independent copy of the variable. Used to solve the problem of data isolation between multiple threads.

Usage scenarios

ThreadLocal is used in many open source frameworks:

  • Spring in the transaction manager, such as TransactionSynchronizationManager, etc.
  • The ErrorContext class in Mybatis uses ThreadLocal to implement a thread-safe singleton.
  • Stores session parameters such as user information.

API

ThreadLocal provides four common methods:

  • set()Method to set a copy of a variable in the current thread.
  • get()Method to obtainThreadLocalA copy of a variable held in the current thread.
  • remove()Method to clear the copies of variables in the current thread.
  • initialValue()Is aprotectedMethod, which is usually used to override, is called when there is no setgetTo callinitialValueMethod to initialize the content.
Private static ThreadLocal < SimpleDateFormat > simpleDateFormatThreadLocal = new ThreadLocal < SimpleDateFormat > () {/ / rewrite this method, Initialize ThreadLocal value @override protected SimpleDateFormat initialValue() {return new SimpleDateFormat(" YYYY-MM-DD HH:mm:ss"); }};Copy the code

The principle of

So how to achieve data isolation, we analyze from the point of view of source code.

Let’s start with the get() method of the ThreadLocal class.

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(); } private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map ! = null) map.set(this, value); else createMap(t, value); return value; } ThreadLocalMap getMap(Thread t) {return t.treadlocals; Void createMap(Thread t, t firstValue) {t.hreadlocals = new ThreadLocalMap(this, firstValue); }Copy the code

As you can see from the source code, data is provided by threadLocals, a member variable of the Thread class

/* ThreadLocal values pertaining to this thread. This map is maintained
 * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
Copy the code

There is a comment written above, which translates to the value of the ThreadLocal for this thread, maintained by the ThreadLocal class.

So it’s clear that data isolation is implemented because the ThreadLocal class operates on Thread’s member variables, threadLocals. Each Thread has its own threadLocals, which does not affect each other.

The threadLocals member variable is essentially a class called ThreadLocalMap, which is an inner class of ThreadLocal. Let’s take a look at the data structure of this inner class.

The data structure

Take a look at the source first:

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 static final int INITIAL_CAPACITY = 16; Private Entry[] table; Private int size = 0; // Load factor private int threshold; private void setThreshold(int len) { threshold = len * 2 / 3; } // The constructor ThreadLocalMap(ThreadLocal<? > firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); }}Copy the code

This looks a bit like a HashMap, except that ThreadLocalMap uses an open addressing method to handle hash collisions. It looks something like this:

So here we see that a reference to a ThreadLocal can be located to a value in the hash table[] of a ThreadLocalMap.

Memory leak problem

We can see from the source code Entry is the inheritance of WeakReference class, key is a WeakReference, value is a strong reference. Why are references designed to be weak? Think about it the other way around, what happens if you make it a strong reference.

If each of the Entry’s keys has a strong reference to a ThreadLocal object, then the ThreadLocal object cannot be collected by GC because it has a strong reference to the Entry object, causing a memory leak, unless the thread is collected after it ends. ThreadLocalMap will follow.

When the Key ThreadLocal object is set to a weak reference object, the ThreadLocal object is collected during system GC.

But will this prevent memory leaks?

It’s not! Since Value is still a strong reference object, when the Key is reclaimed, it becomes null, and Value still has a strong reference chain: Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value can never be reclaimed, and this value can never be accessed, resulting in memory leak.

Get (), set(), and remove() of a ThreadLocal remove all values whose key is null from the thread’s ThreadLocalMap.

conclusion

  • ThreadLocal does not solve the problem of data sharing between multiple threads, but rather makes data copies in different threads, so there is no need to solve the problem of data sharing.
  • Each thread holds a ThreadLocalMap object that is accessed only by the thread holding it, so there is no thread-safety issue.
  • ThreadLocalMap has a data structure similar to HashMap, which consists of Entry[] arrays, sizes, load factors, etc., and uses open addressing to resolve hash conflicts.
  • The Entry of a ThreadLocalMap is a weak reference to a ThreadLocal object. After collection by GC, some values with null keys cannot be accessed or collected, resulting in memory leakage. The precaution is to call the Remove () method of the ThreadLocal to remove the value in the ThreadLocalMap whose key is null.

Thank you very much for your reading, I hope this article can give you help and inspiration.

If you think it’s useful, please give me a thumbs-up. Your thumbs-up is the biggest motivation for my creation

I’m a programmer who tries to be remembered. See you next time!!

Ability is limited, if there is any mistake or improper place, please criticize and correct, study and exchange together!