Local flavor words of love: recommend a 0 card and very sweet snack, my mouth

preface

First of all, what are the application scenarios of ThreadLocal?

In general, ThreadLocal is used in a project to hold information about a user (such as session, etc.). It binds the current user to the current thread and can retrieve this information from anywhere in the same thread.

So what are the downsides of ThreadLocal?

ThreadLocal binds data to the current thread, so what? Yes, if it’s not the same thread, you can’t get data from another thread. The InheritableThreadLocal is designed to solve this problem

How does ThreadLocal store data?

  • ThreadLocal’s set method

    How does the set method save data

    public void set(T value) {
        // Get the current thread object
        Thread t = Thread.currentThread();
        // Get the ThreadLocalMap object maintained by the current thread.
        ThreadLocalMap map = getMap(t);
        if(map ! =null)
            // Save directly
        		map.set(this, value);
        else
            // Create 'ThreadLocalMap' and save it
        		createMap(t, value);
    }
    Copy the code

    Each value is stored in a ThreadLocalMap maintained by each thread and is bound to each thread, so it looks like the same ThreadLocal object is called to store data, but instead of storing data in a ThreadLocal, Instead, they are stored in a ThreadLocalMap maintained by Thread to achieve resource isolation.

  • Data cannot be shared in multiple threads

    Therefore, the data stored in thread A can be retrieved arbitrarily in thread A. However, if A new thread B is opened at this time, the data stored in thread A cannot be retrieved by thread B. Since there are two different threads, when fetching data, you need to fetch the current Thread Thread object, then the ThreadLocalMap maintained by the current Thread, and then the specified data. Thread is not a single Thread, so of course you can’t get data from other threads

    Just look at ThreadLocal’s get method

    public T get(a) {
      	// First get the current thread object
        Thread t = Thread.currentThread();
        // Get the ThreadLocalMap maintained by the current thread object
        ThreadLocalMap map = getMap(t);
        if(map ! =null) {
            // Get the value of the current key(threadLocal object) from 'ThreadLocalMap'
            ThreadLocalMap.Entry e = map.getEntry(this);
        		if(e ! =null) {
                T result = (T)e.value;
                returnresult; }}return setInitialValue();
    }
    Copy the code

How does InheritableThreadLocal pass data?

InheritableThreadLocal InheritableThreadLocal InheritableThreadLocal InheritableThreadLocal InheritableThreadLocal InheritableThreadLocal InheritableThreadLocal InheritableThreadLocal InheritableThreadLocal However, this sharing is one-time, and if the parent thread updates the value of ThreadLocal, the updated data will not be synchronized

  • Sample code for parent and child threads to share data

    private static InheritableThreadLocal<Integer> inheritableThreadLocal = new InheritableThreadLocal<>();
    
    @Test
    public void asyncInherriableThreadLocal(a) {
      	// Save data to InheritableThreadLocal in the main thread
      	inheritableThreadLocal.set(300);
    
      	// Get the data in InheritableThreadLocal in child thread 1
      	new Thread(() -> {
             System.out.println("future1---inheritableThreadLocal:" + inheritableThreadLocal.get());
        }).start();
    		
        TimeUnit.SECONDS.sleep(1);
    		
      	System.out.println("The main - inheritableThreadLocal." + inheritableThreadLocal.get());
    }
    Copy the code

    Console output:

    Future1 inheritableThreadLocal: -- -300The main - inheritableThreadLocal:300
    Copy the code

    Data stored in the main thread is available in thread 1, meaning that the InheritableThreadLocal parent thread can share data

  • How can parent and child threads share data

    • What happens when you create a thread?

      • The first step,new Thread()In the callinit()
      private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
          // Note that the last parameter 'true' is enabled by default
      		init(g, target, name, stackSize, null.true);
      }
      Copy the code
      • The second step is to determine whether it is enableddd, and then executes the one that creates the current threadThreadLocalMap
      private void init(ThreadGroup g, Runnable target, String name,
                            long stackSize, AccessControlContext acc,
                            boolean inheritThreadLocals) {...if(inheritThreadLocals && parent.inheritableThreadLocals ! =null)
      						// Create the 'ThreadLocalMap' object of the current thread and use the 'inheritableThreadLocals' variable maintained by the parent thread
                  this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); . }Copy the code
      • The third step will be the parent threadThreadLocalMapCopies a copy of the data in theThreadLocalMap(This is why InheritableThreadLocal can share data)
      private ThreadLocalMap(ThreadLocalMap parentMap) {
        	// Get the Entry array of the parent thread's 'ThreadLocalMap'
          Entry[] parentTable = parentMap.table;
          int len = parentTable.length;
          setThreshold(len);
          table = new Entry[len];
      		
          // Traverses the Entry array in the parent thread's 'ThreadLocalMap'
          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) {
                      // Get the value of the parent thread
                      Object value = key.childValue(e.value);
                    	// Create a new Entry object to save to 'ThreadLocalMap'
                      Entry c = new Entry(key, value);
                      int h = key.threadLocalHashCode & (len - 1);
                      while(table[h] ! =null)
                          h = nextIndex(h, len);
                      // Save to 'Entry[]' maintained by ThreadLocalMap of the current thread for data transfertable[h] = c; size++; }}}}Copy the code

    The third step is how InheritableThreadLocal passes data from the current thread to the child thread, which is why the child thread doesn’t synchronize updates to the current thread.

A small summary

  • How can data be passed to child threads?

    When a child thread is created in the current thread, the default ThreadLocalMap of the current thread is traversed, and all data in the current thread is copied to the ThreadLocalMap of the new thread

  • Why can’t I synchronize updates?

    Because InheritableThreadLocal does not use a container to copy data to a newly created thread, it can only synchronize data at the time of creation, not update data.

Welcome to the wechat public account “code on the finger tip”

Your likes and attention are the biggest motivation for writing articles