zoukankan      html  css  js  c++  java
  • ThreadLocal (二):什么时候使用 InheritableThreadLocal

    一、ThreadLocal 在父子线程传递的问题

    public class InheritableThreadLocalDemo {
    
    //    全局变量
    //    static ThreadLocal<String> threadLocal = new ThreadLocal<>();
        static ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
    
    
        public static void main(String[] args) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    InheritableThreadLocalDemo.threadLocal.set("superWorld");
                    new Service().call();
                }
            }).start();
        }
    }
    
    
    class Service {
        public void call() {
            System.out.println("Service:" + Thread.currentThread().getName() + " : " + InheritableThreadLocalDemo.threadLocal.get());
            //new Dao().call();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    new Dao().call();
                }
            }).start();
        }
    }
    
    class Dao {
        public void call() {
            System.out.println("Dao:" + Thread.currentThread().getName() + " : " + InheritableThreadLocalDemo.threadLocal.get());
        }
    
    }

    二、InheritableThreadLocal 和 ThreadLocal 的区别

    1. InheritableThreadLocal 实现

    public class InheritableThreadLocal<T> extends ThreadLocal<T> {
        /**
         * Computes the child's initial value for this inheritable thread-local
         * variable as a function of the parent's value at the time the child
         * thread is created.  This method is called from within the parent
         * thread before the child is started.
         * <p>
         * This method merely returns its input argument, and should be overridden
         * if a different behavior is desired.
         *
         * @param parentValue the parent thread's value
         * @return the child thread's initial value
         */
        protected T childValue(T parentValue) {
            return parentValue;
        }
    
        /**
         * Get the map associated with a ThreadLocal.
         *
         * @param t the current thread
         */
        ThreadLocalMap getMap(Thread t) {
           return t.inheritableThreadLocals;
        }
    
        /**
         * Create the map associated with a ThreadLocal.
         *
         * @param t the current thread
         * @param firstValue value for the initial entry of the table.
         */
        void createMap(Thread t, T firstValue) {
            t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
        }
    }

      

    2. ThreadLocal 的getMap、createMap实现

        /**
         * Get the map associated with a ThreadLocal. Overridden in
         * InheritableThreadLocal.
         *
         * @param  t the current thread
         * @return the map
         */
        ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
        }
    
        /**
         * Create the map associated with a ThreadLocal. Overridden in
         * InheritableThreadLocal.
         *
         * @param t the current thread
         * @param firstValue value for the initial entry of the map
         */
        void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }

    通过上面的代码我们可以看到InheritableThreadLocal 重写了childValue, getMap,createMap三个方法,

    当我们往里面set值的时候,值保存到了inheritableThreadLocals里面,而不是之前的threadLocals。

    三、问题:为什么当创建子线程时,可以获取到上个线程里的threadLocal中的值呢?

    原因就是在新创建线程的时候,会把之前线程的inheritableThreadLocals赋值给新线程的inheritableThreadLocals,通过这种方式实现了数据的传递。

    代码关键点:

    1. Thread#init

    if (parent.inheritableThreadLocals != null)
                this.inheritableThreadLocals =  ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

    2. ThreadLocal.createInheritedMap

           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++;
                        }
                    }
                }
            }
  • 相关阅读:
    一次脑残的记录: Linux 中实时任务调度与优先级
    这 7 个 Linux 命令,你是怎么来使用的?
    物联网设备OTA软件升级之:完全升级和增量升级
    物联网设备OTA软件升级之:升级包下载过程之旅
    Linux应用程序设计:用一种讨巧方式,来获取线程栈的使用信息
    Linux系统中编译、链接的基石-ELF文件:扒开它的层层外衣,从字节码的粒度来探索
    应用程序设计:在动态库中如何调用外部函数?
    Typescript学习笔记
    gRPC 重试策略
    Gogs+Jenkins+Docker 自动化部署.NetCore
  • 原文地址:https://www.cnblogs.com/yuyutianxia/p/3983507.html
Copyright © 2011-2022 走看看