InheritableThreadLocal 用法

Foreword

Introduced earlier ThreadLocal usage, by threadLocal a value in the same thread pass, but father and son in the thread can not be passed by value, and because it is not the same thread, so the corresponding ThreadLocalMap is not the same

Examples

ThreadLocal example

public class ThreadLocalTest {
    public static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static String get() {
        return threadLocal.get();
    }

    public static void set(String value) {
        threadLocal.set(value);
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            final int j = i;
            ThreadLocalTest.set("ye");
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + ":" + ThreadLocalTest.get());
                }
            });

            t.start();
        }
    }
}
复制代码

result:

InheritableThreadLocal example

public class InheritableThreadLocalTest {
    public static ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();

    public static String get() {
        return threadLocal.get();
    }

    public static void set(String value) {
        threadLocal.set(value);
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            InheritableThreadLocalTest.set("ye");
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + ":" + InheritableThreadLocalTest.get());
                }
            });

            t.start();
        }
    }
}
复制代码

result:

Resolve

InheritableThreadLocal inherited ThreadLocal 
look at his set method, set by calling the set method ThreadLocal
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
复制代码

createMap calls itself overridden

void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }
复制代码

See above discovery and the ThreadLocal createMap almost initialize a ThreadLocalMap, just assigned to the inheritableThreadLocals, and ThreadLocal assigned to the threadLocals

Continue to look at the get method, get method is invoked ThreadLocal get methods

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();
    }
复制代码

The difference is that getMap call is overridden method InheritableThreadLocal

ThreadLocalMap getMap(Thread t) {
       return t.inheritableThreadLocals;
    }
复制代码

Because the assignment to the set time is t.inheritableThreadLocals, so take the map of the time it was taken from t.inheritableThreadLocals

After reading the set and get methods, the only difference is where the map is not the same access, but can not see it different from the other, but a change only one variable, and how he was not the same ThreadLocal, is how to complete the value of parent-child thread That depends Thread pass it initializes, look at the Thread class constructor you will see invokes an init method

Thread init method

private void init(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 doesn't have a strong opinion of 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(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);
        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 */
        tid = nextThreadID();
    }
复制代码

The above method is mainly to see

if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
复制代码

inheritThreadLocals is the reference method, only to see the constructor Thread (Runnable target, AccessControlContext acc) is false, the rest of the construction methods are true, it is true that we pass here

Thread(Runnable target, AccessControlContext acc) {
        init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
    }
复制代码
Thread parent = currentThread (); 
in this case is our main thread, because we are using in the main there is InheritableThreadLocalTest.set ( "ye"); 
so we put ThreadLocalMap assigned to the inheritableThreadLocals 
sum will go this.inheritableThreadLocals = 
                ThreadLocal.createInheritedMap (parent.inheritableThreadLocals); 
the this new child thread of the current                 

Then we must look inheritableThreadLocals child thread is how the assignment

 static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
        return new ThreadLocalMap(parentMap);
    }
    
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++;
                    }
                }
            }
        }    
复制代码

The code is very simple, is to get ThreadLocalMap parent thread, and copy (shallow copy, copy reference), such child threads have a corresponding ThreadLocalMap inheritableThreadLocals, so that the same value can be taken and the parent thread by ThreadLocalMap

summary

InheritableThreadLocal inheritance ThreadLocal, ThreadLocal so usage and, as 
the only difference is ThreadLocal using a ThreadLocal variable using a ThreadLocal.ThreadLocalMap threadLocals 
InheritableThreadLocal use the ThreadLocal.ThreadLocalMap inheritableThreadLocals variable 
but they are ThreadLocalMap, so the get and set essentially no difference the 
InheritableThreadLocal reason why his son can support direct transfer thread 
is init copied when the parent thread new thread of the ThreadLocalMap to inheritableThreadLocals child thread in

Guess you like

Origin juejin.im/post/5d15d36df265da1bc37f229a