“This is the third day of my participation in the First Challenge 2022. For details: First Challenge 2022”

A:

We know ThreadLocal can implement thread-level data isolation, but if we need to pass the value of the current thread to the child thread, we need to write our own logic, which can be complicated. InheritableThreadLocal helps us solve this problem. In this article, we’ll talk about InheritableThreadLocal.

[InheritableThreadLocal] [InheritableThreadLocal

1. How is data stored

We can see that InheritableThreadLocal inherits ThreadLocal and overrides ThreadLocal’s getMap() and createMap() methods. GetMap () returns the inheritableThreadLocals member of Thread. CreateMap () creates a ThreadLocalMap and assigns it to the inheritableThreadLocals member of the current Thread. So InheritableThreadLocal’s get(), set(), and remove() methods are inherited from ThreadLocal. InheritableThreadLocal is stored in the inheritableThreadLocals member of the Thread.

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
    
    protected T childValue(T parentValue) {
        return parentValue;
    }

    // Returns the inheritableThreadLocals member of the current thread
    ThreadLocalMap getMap(Thread t) {
       return t.inheritableThreadLocals;
    }

    // Create a ThreadLocalMap and assign it to the inheritableThreadLocals
    void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue); }}Copy the code

Note: The ThreadLocal principle is covered thoroughly in my other article, but I won’t elaborate on it here

2. How is data passed to child threads?

In the thread constructor, the init() method is invoked, and the createInheritedMap() method is called in init() to initialize the child’s inheritableThreadLocals, And take the inheritableThreadLocals value from the parent thread and assign it to the inheritableThreadLocals value from the child thread.

public Thread(a) {
        init(null.null."Thread-" + nextThreadNum(), 0);
    }
Copy the code
private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null.true);
    }
Copy the code
private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {... Other unrelated source code some assignment operations are omitted here for space//inheritThreadLocals is true by default
        // If passing is required and the inheritableThreadLocals of the parent thread is not null
        if(inheritThreadLocals && parent.inheritableThreadLocals ! =null)
        // Initialize inheritableThreadLocals and pass the value from the parent thread's inheritableThreadLocals to the child thread
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        this.stackSize = stackSize;

        /* Set thread ID */
        tid = nextThreadID();
    }
Copy the code

Next we examine the createInheritedMap() method

createInheritedMap()

The createInheritedMap() method calls the parameter constructor of ThreadLocalMap.

static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
        return new ThreadLocalMap(parentMap);
    }
Copy the code

In the constructor, the inheritableThreadLocals of the parent thread is iterated over, and the inheritableThreadLocals Entry array of the parent thread is rewrapped as an Entry, And compute the array subscript into the inheritableThreadLocals of the child thread. This passes data from the parent thread to the child thread.

private ThreadLocalMap(ThreadLocalMap parentMap) {
            Entry[] parentTable = parentMap.table;
            int len = parentTable.length;
            setThreshold(len);
            table = new Entry[len];
            // Iterate through the parent thread's inheritableThreadLocals Entry array
            for (int j = 0; j < len; j++) {
                Entry e = parentTable[j];
                if(e ! =null) {
                    @SuppressWarnings("unchecked")
                    ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
                    // If the key is null, the data is invalid and does not need to be passed to the child thread
                    if(key ! =null) {
                        // Fetch the value of the parent thread
                        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

Conclusion:

The inheritableThreadLocals data is stored in the inheritableThreadLocals constructor, and the inheritableThreadLocals value is copied from the parent Thread’s inheritableThreadLocals value. Save it in your own inheritableThreadLocals, which completes the data transfer between parent and child threads.

If it helps you, just give it a thumbs up and leave.