ThreadLocal原理

2018-03-20  本文已影响0人  一只胖Wa牛

首先要带着问题去分析,

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);
    }
    ...
}

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);
        }
    }
    ...
}

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

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
           map.set(this, value);
        else
           createMap(t, value);
    }

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

上一篇下一篇

猜你喜欢

热点阅读