美文网首页
ThreadLocal原理

ThreadLocal原理

作者: 一只胖Wa牛 | 来源:发表于2018-03-20 16:16 被阅读0次

    首先要带着问题去分析,

    • 新城变量的副本存储在那里?
    • 变量副本是怎么从共享的那个变量赋值出来的?源码中的threadlocal是什么时候初始化的

    ThreadLocal是如何实现多个线程之间每一个线程都持有该线程都变量副本?如何共享变量的

    ThreadLocal提供了set和get方法用来访问当前线程的线程局部变量

    public class ThreadLocal<T> {
        ...
        /**
        * Returns the value in the current thread's copy of this
        * thread-local variable.  If the variable has no value for the
        * current thread, it is first initialized to the value 
        * returned
        * by an invocation of the {@link #initialValue} method.
        *
        * @return the current thread's value of this thread-local
        */
        public T get() {
           //获取当前线程
           Thread t = Thread.currentThread();
           //拿到线程中的存储变量副本
           ThreadLocalMap map = getMap(t);
           if (map != null) {
               ThreadLocalMap.Entry e = map.getEntry(this);
               if (e != null)
                   return (T)e.value;
           }
           //如果当前线程中的ThreadLocalMap == null就进行初始化的操作
           return setInitialValue();
        }
    
        private T setInitialValue() {
           T value = initialValue();
           Thread t = Thread.currentThread();
           ThreadLocalMap map = getMap(t);
           if (map != null)
               map.set(this, value);
           else
               createMap(t, value);
           return value;
        }
        
        protected T initialValue() {
            return null;
        }
    
        ThreadLocalMap getMap(Thread t) {
           return t.threadLocals;
        }
        
        void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
        ...
    }
    
    • 首先看ThreadLocal类的成员函数get方法的注解,返回当前线程的变量副本,如果当前线程不存在变量副本,那么就初始化一个容量为0的变量副本
    • 分析ThreadLocal类的成员函数get可知,首先根据当前线程去获取它的成员变量threadLocals,他的类型为ThreadLocalMap是ThreadLocal的一个内部类。接下来赋值给局部变量map,紧接着执行map != null,如果是首次执行,此时map==null,那么接下来就会调用ThreadLocal类的成员函数setInitialValue去进行初始化的操作,跟踪代码最终执行到了成员函数createMap,也就是创建了一个ThreadLocalMap的实例并赋值给了当前线程t的成员变量threadLocals;如果不是第一次的操作,那么此时map != null是成立的,那么此时就可以根据ThreadLocal实例直接获取到存储到变量副本

    ThreadLocalMap解析

    public class ThreadLocal<T> {
        ...
        static class ThreadLocalMap {
            
            static class Entry extends WeakReference<ThreadLocal> {
                /** The value associated with this ThreadLocal. */
                Object value;
    
                Entry(ThreadLocal k, Object v) {
                    super(k);
                    value = v;
                }
            }
            ...
            private static final int INITIAL_CAPACITY = 16;
            ...
            ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
                table = new Entry[INITIAL_CAPACITY];
                int i = firstKey.threadLocalHashCode & 
                    (INITIAL_CAPACITY - 1);
                table[i] = new Entry(firstKey, firstValue);
                size = 1;
                setThreshold(INITIAL_CAPACITY);
            }
        }
        ...
    }
    
    • 可以看到ThreadLocalMapThreadLocal的一个内部类,然后还有一个内部类Entry,ThreadLocalMap构造初始化时候,创建了一个size = 16的Entry数据,并且把当前线程持有的ThreadLocal对象作为key传入,当前线程的便利那个副本作为value传入,并存入数据中去,这样子就可以关联起来ThreadLocal与当前线程的变量副本
    • 总结下来其实每个线程的变量副本是存放在自己的成员变量threadLocals中,他的类型是ThrealLocalMap,然后通过ThreadLocal去访问对应的变量副本

    变量副本是什么时候创建出来的呢?

        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
               map.set(this, value);
            else
               createMap(t, value);
        }
    
    • 当前线程中的threadLocalMap是null的时候,会调用createMap创建一个新的map,并且赋值给当前的线程的成员变量threadLocals

    总结如下:
    1、在代码中声明的ThreadLocal对象,实际上只有一个。
    2、在每个线程中,都维护了一个threadlocals对象,在没有ThreadLocal变量的时候是null的。一旦在ThreadLocal的createMap函数中初始化之后,这个threadlocals就初始化了。以后每次那个ThreadLocal对象想要访问变量的时候,比如set函数和get函数,都是先通过getMap(t)函数,先将线程的map取出,然后再从这个在线程(Thread)中维护的map中取出数据【以当前threadlocal作为参数】。

    相关文章

      网友评论

          本文标题:ThreadLocal原理

          本文链接:https://www.haomeiwen.com/subject/vdebqftx.html