ThreadLocal, there are a lot of articles on the web, and most people use it, but they don’t necessarily use it well or really understand it

ThreadLocal

ThreadLocal itself does not act as a storage container. Instead, ThreadLocal stores values in variables in the current Thread.

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

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

One wonders why there are 2 objects, threadLocals is what we normally use, and inheritableThreadLocals is what we use when the current thread opens a child thread, so that the child thread can also use the current thread’s threadLocals object, Use InheritableThreadLocal with a subclass that uses ThreadLocal, as described in the next section

If threadLocals is null, you will not be able to locate the assignment to Thread because the assignment is provided by the ThreadLocal class:

  /**
     * Create the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the map
     */
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }Copy the code

As shown above, the threadLocals variable is assigned to the current thread, and the key is this, which is the current ThreadLocal object

Note that ThreadLocalMap is used. This class is similar to HashMap, but it doesn’t implement any interface. This class is in ThreadLocal and is defined as static class ThreadLocalMap, but its methods are private. This means that this class is used only by ThreadLocal

Internally, it uses user-defined Entry objects to store data. Entry classes are as follows:

static class Entry extends WeakReference<ThreadLocal<? >> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<? > k, Object v) { super(k); value = v; }}Copy the code

Inherit WeakReference, see the construction method, we can know that key is WeakReference type, value is a common strong reference

This means that, if there are no other references, the key will be automatically reclaimed when the thread terminates, and the ThreadLocal will be reclaimed, seemingly perfectly

But in general, our use methods are similar to the following:

public abstract class ThreadContext {

    private static final ThreadLocal<Map<Object, Object>> resources = new InheritableThreadLocalMap<>();

}Copy the code

With the static modifier, references are still available even after the thread terminates, so they are not collected

Also, a lot of the time we use thread pools, it’s possible that the thread will never terminate and ThreadLocal objects will never be collected

In both cases, memory leaks and logic errors are possible, so it is best practice to display the remove method of ThreadLocal when you are done using it

InheritableThreadLocal

Use InheritableThreadLocal as follows:

public class Test { public static ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<Integer>(); public static void main(String args[]){ threadLocal.set(new Integer(123)); Thread thread = new MyThread(); thread.start(); System.out.println("main = " + threadLocal.get()); } static class MyThread extends Thread{ @Override public void run(){ System.out.println("MyThread = " + threadLocal.get()); }}}Copy the code

Output:

main = 123

MyThread = 123Copy the code

The child thread perfectly uses the parent thread’s object. How does this work?

[InheritableThreadLocal] [InheritableThreadLocal] [InheritableThreadLocal]

public class InheritableThreadLocal<T> extends ThreadLocal<T> { protected T childValue(T parentValue) { return parentValue; } ThreadLocalMap getMap(Thread t) { return t.inheritableThreadLocals; } void createMap(Thread t, T firstValue) { t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue); }}Copy the code

Inherits ThreadLocal, overrides the parent class’s getMap method, and returns the inheritableThreadLocals member of Thread, which is the other member of Thread

It also overrides the createMap method, which is also assigned to the inheritableThreadLocals member of the parent class

[inheritableThreadLocals] [inheritableThreadLocals] [inheritableThreadLocals] [Thread locals] [inheritableThreadLocals] [Thread locals] Subclasses follow the parent’s framework to perform a defined process, but some of the details can have their own implementation

If we look at the constructor for Thread, it calls various init methods, all of which end up calling the following init method, and the inheritThreadLocals parameter is true. Thread(Runnable target, AccessControlContext acc) The constructor that calls the init method inheritThreadLocals is false, but is not public.

private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) { ... Thread parent = currentThread(); if (inheritThreadLocals && parent.inheritableThreadLocals ! = null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); . } static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) { return new ThreadLocalMap(parentMap); }Copy the code

If inheritThreadLocals is true and the current thread’s inheritableThreadLocals value is not empty, So to assign the inheritableThreadLocals value, let’s look at the new ThreadLocalMap constructor that’s called

private ThreadLocalMap(ThreadLocalMap parentMap) {
            Entry[] parentTable = parentMap.table;
            int len = parentTable.length;
            setThreshold(len);
            table = new Entry[len];

            for (int j = 0; j < len; j++) {
                Entry e = parentTable[j];
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
                    if (key != null) {
                        Object value = key.childValue(e.value);
                        Entry c = new Entry(key, value);
                        int h = key.threadLocalHashCode & (len - 1);
                        while (table[h] != null)
                            h = nextIndex(h, len);
                        table[h] = c;
                        size++;
                    }
                }
            }
        }Copy the code

If you have seen the source code of HashMap, you know that the Entry in the list is a linked list, because there are duplicate keys. Why not here?

If you look at line 16 and 17, if you already have a value for position H, then in an infinite loop, you regenerate position H until there is no value for position H, so you don’t need a list

In line 13, Object value = key.childValue(e.value);

This method in ThreadLocal looks like this:

T childValue(T parentValue) {
        throw new UnsupportedOperationException();
    }Copy the code

[InheritableThreadLocal] [InheritableThreadLocal] [InheritableThreadLocal] [InheritableThreadLocal] [InheritableThreadLocal] [InheritableThreadLocal]

protected T childValue(T parentValue) {
        return parentValue;
    }Copy the code

If you want to use the InheritableThreadLocal class to override the InheritableThreadLocal childValue method, then you can make a deep copy of the InheritableThreadLocal class. Note the deep copy

other

It can also be seen from the above analysis

  1. You can use both a ThreadLocal and an InheritableThreadLocal Thread in the same Thread. These variables are unique to each other, but InheritableThreadLocal is inherited by subclasses
  2. You can use multiple ThreadLocal objects without affecting each other, because the key of a ThreadLocalMap is the ThreadLocal itself. Many people would think that the key of a ThreadLocalMap is the current Thread. You can’t use multiple ThreadLocal objects at the same time; the latter overwrites the former
  3. When using InheritableThreadLocal, you can override the childValue method for a deep copy

The original link