One, foreword

In everyday work, ThreadLocal is often used to avoid thread concurrency problems. Each thread accesses its own local variables, with no contention, no locking, and very efficient. Now we have a business scenario where we need to create child threads to perform tasks. The parent thread sets the value of ThreadLocal and wants to get it from the child thread. Can we get it? The answer is: no.

If the parent thread is a set, then the local map is in the parent thread, and the child thread’s threadLocals is null, how can you get the set from the child thread?

But that’s what the requirement is. How do you implement it? Copy the parent thread’s ThreadLocalMap to the child thread? Yes, Java officials think so too!

Second, the InheritableThreadLocal

1. Method of use

Java uses an InheritableThreadLocal class that uses exactly the same name as a ThreadLocal class. Replace the InheritableThreadLocal with an InheritableThreadLocal and get the value of the parent thread’s set from the child thread.

2. Inheritance

How does InheritableThreadLocal do that? See the real knowledge under the source code:

package java.lang;
/ * * *@author  Josh Bloch and Doug Lea
 * @see     ThreadLocal
 * @since1.2 * /
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 overwrites the methods childValue, getMap, and createMap. InheritableThreadLocals uses the variable inheritableThreadLocals. That’s ThreadLocalMap InheritableThreadLocal initialization assigned to t.i nheritableThreadLocals, set and get is also operating t.i nheritableThreadLocals.

public class Thread implements Runnable {... . ThreadLocal.ThreadLocalMap threadLocals =null;
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; . . }Copy the code

3. Replication principle

How do you copy the parent thread’s map to the child thread?

To trace Thread initialization, init() is called. Init initializes a lot of things.

InheritThreadLocals =true when creating child threads, the parent thread inheritableThreadLocals =true when creating child threads. =null, the inheritableThreadLocals of the parent thread is copied to the child thread.

// java.lang.ThreadLocal#createInheritedMap
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
    return new ThreadLocalMap(parentMap);
}
Copy the code
//java.lang.ThreadLocal.ThreadLocalMap#ThreadLocalMap
private ThreadLocalMap(ThreadLocalMap parentMap) {
    Entry[] parentTable = parentMap.table;
    int len = parentTable.length;
    setThreshold(len);
    table = new Entry[len];
    // Iterate over the copy
    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) {
                // InheritableThreadLocal overrides childValue
                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

3. What is childValue

In ThreadLocal, childValue is not implemented, and in InheritableThreadLocal, it is simply implemented.

//java.lang.ThreadLocal#childValue
T childValue(T parentValue) {
    throw new UnsupportedOperationException();
}
Copy the code
//java.lang.InheritableThreadLocal#childValue
protected T childValue(T parentValue) {
    return parentValue;
}
Copy the code

What is the purpose of copying ThreaLocalMap from parent thread to child thread when the value is passed from childValue to Entry? [InheritableThreadLocal] [childValue] [InheritableThreadLocal] [childValue] [childValue] [InheritableThreadLocal] Although InheritableThreadLocal does nothing, users can override childValue by InheritableThreadLocal, doing special processing for the value. Why would you want to do something special for value?

For example, if the value is set to a custom reference type, then the value copied from the parent thread to multiple child threads will have concurrency problems (value passing, address values are shared), so make sure that the address values copied to each child thread are different. InheritableThreadLocal implements a deep copy of the InheritableThreadLocal childValue.

public class MyInheritableThreadLocal<T> extends InheritableThreadLocal<T>{
    protected T childValue(T parentValue) {
        System.out.println("MyInheritableThreadLocal。。。");
        / / copy
        Gson gson = new Gson();
        String s = gson.toJson(parentValue);
        return(T)gson.fromJson(s, parentValue.getClass()); }}Copy the code
public class InheritableThreadLocalTest {
    public static void main(String[] args) throws InterruptedException {
        InheritableThreadLocal<Stu> itl = new MyInheritableThreadLocal<Stu>();
        itl.set(new Stu());
        System.out.println(Parent thread: + itl.get().toString());
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run(a) {
                System.out.println(Child thread 1:+ itl.get().toString()); }}); thread1.start(); Thread thread2 =new Thread(new Runnable() {
            @Override
            public void run(a) {
                System.out.println(Child thread 2:+ itl.get().toString()); }}); thread2.start(); }static class Stu {
        private String name = "xxx"; }}// Console printsParent: com. Stefan. DailyTest. InheritableThreadLocalTest $Stu @49476842MyInheritableThreadLocal... The child thread1: com. Stefan. DailyTest. InheritableThreadLocalTest $Stu @ 7446 b2ac MyInheritableThreadLocal... The child thread2: com. Stefan. DailyTest. F4c190 InheritableThreadLocalTest $Stu @ 75Copy the code

Four,

  1. InheritableThreadLocalIt is possible for a child thread to get a local variable from a parent thread.
  2. Local variable of the parent thread (current thread) when the child thread is initializedinheritableThreadLocalsIf it is not null, it is copied to the child thread.
  3. ThreadLocalLeave achildValueThe idea is to letInheritableThreadLocalImplementation, and can let the client custom rewritechildValueSpecial handling of values copied from parent to child threads.
  4. If used by the parent threadInheritableThreadLocalIf the value of a custom reference type is set, there is a concurrency problem when copying it to a child threadchildValueDeep copy of.

Here’s a question:

If a thread pool is used to create a child thread, the child thread is initialized only once, and the parent thread uses InheritableThreadLocal to set the value. Because the replication mechanism is set at thread initialization time, the parent thread can only synchronize the data once when the thread pool initializes the child thread, and the parent thread can modify the value later. Can’t synchronize updates to child threads in the thread pool?

The solution is to use the thread pool and InheritableThreadLocal to create a replication mechanism at every task submission. We have an open source project to provide a solution github.com/alibaba/tra…

PS: If there is any misunderstanding in this article, we welcome your criticism and correction, and look forward to your comments, likes and favorites. I am Xu, willing to make progress with you!

Sky blue and so on misty rain, and I am waiting for you, wechat public number search: Xu students ah, continue to update liver goods, come to pay attention to me, and I study together ~