• 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++;
                        }
                    }
                }
            }
  • 相关阅读:
    SQL Server 存储过程/触发器中调用COM组件的方法
    写入Stream
    Python 3.2 中adodbapi的问题
    Python中将系统输出显示在PyQt中
    动态创建 Lambda 表达式
    Entity Framework框架Code First Fluent API
    扩展IQueryable实现属性名称排序
    在Entity Framework中使用事务
    ASP.NET MVC:通过FileResult向浏览器发送文件
    ASP.NET MVC: 使用自定义 ModelBinder 过滤敏感信息
  • 原文地址:https://www.cnblogs.com/yuyutianxia/p/3983507.html
Copyright © 2020-2023  润新知