This is the 19th day of my participation in the First Challenge 2022

A list,

As mentioned above, some thread variables can be stored in a ThreadLocal, but how to pass a thread variable to a child thread if the parent thread is a time-consuming thread and needs to use a child thread to perform time-consuming operations? This is because the parent thread cannot always pass thread variables as parameters. In addition to the attributes in the Thread threadLocals reference ThreadLocal. ThreadLocalMap, actually also has an attribute, namely inheritableThreadLocals, threadLocals role is to save the Thread local variable, The inneritableThreadLocals function is to transfer the InheritableThreadLocal variable of the current thread to the InheritableThreadLocal variable of the child thread.

Second, the instance
public static void main(String[] args) throws InterruptedException {
  InheritableThreadLocal<String> username = new InheritableThreadLocal<>();
  ThreadLocal<String> password = new ThreadLocal<>();
  username.set("zhangShang");
  password.set("123456789");

  new Thread(new Runnable() {
    @Override
    public void run(a) {
      System.out.println(username.get());
      System.out.println(password.get());
    }
  }).start();
}
Copy the code

The output is:

zhangShang
null
Copy the code

So we basically conclude that InheritableThreadLocal has parent-child delivery, and ThreadLocal doesn’t have parent-child delivery.

Third, the principle of
1. InheritableThreadLocalThe implementation of the

InheritableThreadLocal inherits from ThreadLocal and overwrites the three methods in ThreadLocal.

  • childValue: This interface isThreadLocal openInterface, which is thrown by defaultUnsupportedOperationExceptionThe exception. Implementatively, only the input parameter is returned; invocatively, it is used when the child thread is created.
  • getMap: rewritegetMap, the operationInheritableThreadLocal, only thread objects will be affectedThreadtheinheritableThreadProperties.
  • createMap: with the above access methodgetMapThe situation is the same.
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
2. Thread creation process

Trace the new Thread() method.

1. Enter the initialization method.

public Thread(a) {
  init(null.null."Thread-" + nextThreadNum(), 0);
}
Copy the code

2. Call the init method.

Override the corresponding init method, then use the current thread (the parent thread) to get the corresponding ThreadLocalMap, which is then passed to the inheritableThreadLocals

// Override the method
private void init(ThreadGroup g, Runnable target, String name,long stackSize) {
  init(g, target, name, stackSize, null.true);
}

// Finally, the method is actually called
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;
  // Parent thread is the current thread that creates the child thread.Thread parent = currentThread(); . Omit some code not relevant to this chapter// inheritThreadLocals=true, the default is true, and the parent thread's inheritableThreadLocal object is not empty
  Create an inheritableThreadLocals object for the current thread.
  if(inheritThreadLocals && parent.inheritableThreadLocals ! =null)
    this.inheritableThreadLocals =
    ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
  this.stackSize = stackSize;
  tid = nextThreadID();
}
Copy the code

3. Access the createInheritedMap method.

Create an inheritableThreadLocals object for the child thread using the parent thread’s inheritableThreadLocals as an instance, and copy the parent thread’s inheritableThreadLocals loop to the child thread.

static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
  Create a ThreadLocalMap object using the inheritableThreadLocals of the parent thread
  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) {
        // As to why key.childValue() is used here, the inner logic is simply to return the input parameter.
        // Some people on the Internet say it is to make the code easier to read, which I think is a bit far-fetched. Feeling is in order to gain
        // Do some small transformations in the process?
        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
Four, thinking

The parent process uses the inheritableThreadLocals attribute to transfer local variables. In practical application scenarios, the parent process does not directly create child processes to handle asynchronous or time-consuming operations. Thread pools are usually used. Is inheritableThreadLocal still valid if you use a thread pool? Consider writing a demo and running it to see how it works, which will be explained in the next article.