Make sure you already know about ThreadLocal before you know about InheritableThreadLocal

We know ThreadLocal can pass values between threads, but what about parent-child threads?

Let’s look at a simple example

		private static final ThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();
    private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();

public static void main(String[] args) throws InterruptedException {
        testInheritableThreadLocal();
    }

    public static void testInheritableThreadLocal(a) {
        inheritableThreadLocal.set("set-inheritableThreadLocal");
        threadLocal.set("set-threadLocal");
        new Thread(() -> {
            String threadLocalCtx = threadLocal.get();
            String inheritableThreadLocalCtx = inheritableThreadLocal.get();
            System.out.println("currentThread:" + Thread.currentThread() + ", get threadLocalCtx:" + threadLocalCtx);
            System.out.println("currentThread:" + Thread.currentThread() + ", get inheritableThreadLocalCtx:" + inheritableThreadLocalCtx);
        }).start();
    }
Copy the code

Output result:

[InheritableThreadLocal] [InheritableThreadLocal] [parent thread] [parent thread] [parent thread] [parent thread] [parent thread] [parent thread] [parent thread] [parent thread] [parent thread

How does InheritableThreadLocal do that? Let’s take a quick look

Type of UML diagram

You can see that InheritableThreadLocal inherits from ThreadLocal

Core source code analysis

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

InheritableThreadLocal overrides several methods with ThreadLocal

  public T get(a) {
        Thread t = Thread.currentThread();
    		// This method is overridden and actually calls the InheritableThreadLocal GET method
        ThreadLocalMap map = getMap(t);
        if(map ! =null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if(e ! =null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                returnresult; }}return setInitialValue();
    }

ThreadLocalMap getMap(Thread t) {
       return t.inheritableThreadLocals;
    }
Copy the code

Can you see that there’s nothing special about ThreadLocal

We can look at the get method of ThreadLocal

public T get(a) {
        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;
                returnresult; }}return setInitialValue();
    }

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
Copy the code

When you get a ThreadLocalMap you get an inheritableThreadLocals which is a ThreadLocalMap just like ThreadLocal

So where is the core code that implements parent-child thread value passing? In the Thread constructor, let’s take a look

Core principles

Here are the Thread constructors, calling constructor overloads for different parameters. Let’s go straight to the implementation class

private Thread(ThreadGroup g, Runnable target, String name,
                   long stackSize, AccessControlContext acc,
                   boolean inheritThreadLocals) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;

        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
            /* Determine if it's an applet or not */

            /* If there is a security manager, ask the security manager what to do. */
            if(security ! =null) {
                g = security.getThreadGroup();
            }

            /* If the security manager doesn't have a strong opinion on the matter, use the parent thread group. */
            if (g == null) { g = parent.getThreadGroup(); }}/* checkAccess regardless of whether or not threadgroup is explicitly passed in. */
        g.checkAccess();

        /* * Do we have the required permissions? * /
        if(security ! =null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(
                        SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }

        g.addUnstarted();

        this.group = g;
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext = acc ! =null ? acc : AccessController.getContext();
        this.target = target;
        setPriority(priority);
  			// Core code
        if(inheritThreadLocals && parent.inheritableThreadLocals ! =null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

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

The core code

if(inheritThreadLocals && parent.inheritableThreadLocals ! =null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
Copy the code

You can see that the parent thread’s ThreadLocalMap is passed to the child thread’s ThreadLocalMap when the child thread is created

It is important to note that once the child thread has been created, the child thread will not be aware that it is manipulating the ThreadLocal variable in the parent thread. Since the parent thread and child thread still have their own ThreadLocalMap, they just copy the parent thread’s ThreadLocalMap to the child thread through the constructor when the child thread is created

Feel good article welcome to pay attention to the public number: small play technology