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++;
                        }
                    }
                }
            }
  • 相关阅读:
    typora的使用
    kibana解决Kibana server is not ready yet问题
    docker详细
    docker 启动报错:Docker.Core.Backend.BackendException: Error response from daemon: open \.pipedocker_e
    win10的docker配置nginx
    lombok常用注解
    关于前端项目cookie的获取
    使用apt安装docker
    linux下root用户和普通用户切换
    deepin系统安装与linux磁盘分区
  • 原文地址:https://www.cnblogs.com/yuyutianxia/p/3983507.html
Copyright © 2011-2022 走看看