ThreadLocal理解分析

300 阅读3分钟

ThreadLocal

是一种解决多线程环境下成员变量问题的一个解决方案,与线程同步无关。

1. 设计思路:

为每个线程创建一个属于线程自己的变量副本,从而每个线程都可以独立的改变自己所拥有的副本,而不会影响其他线程所对应的副本。

白话:ThreadLocal说白了,就是为每个线程自己提供了一个新的副本对象,各自线程拥有各自的,这样就不会对别人有任何妨碍了。

2. 为啥需要引用ThreadLocal ?

不是为了解决共享变量问题,也不是为了线程同步而存在,而是为了便于每个线程能够处理自己的状态而引入的一种机制。

3. 主要方法

3.1 get()

返回该线程局部变量的当前线程的副本的值

3.2 initialValue()

返回该线程局部变量副本的初始值

3.3 remove()

移除当前线程局部变量副本值

3.4 set(T v)

将此线程局部变量的当前副本中的值设置为指定值

4. ThreadLocalMap

实现该机制的关键内部类,属于ThreadLocal中的内部类

ThreadLocalMap 是一种定制的哈希映射,仅适用于维护线程本地值。 不会在 ThreadLocal 类之外导出任何操作。 该类是包私有的,以允许在类 Thread 中声明字段。 为了帮助处理非常大且长期存在的用法,哈希表条目使用.

在Thread类中位置

/* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
  1. 在Thread类中维护了这样ThreadLocal.ThreadLocalMap一个类型的成员变量,该成员变量用来存储实际的ThreadLocal变量副本。
  2. 提供了一种用键值对方式存储每个线程变量副本的方法,key为当前ThreadLocal对象,value则是对呀线程的变量副本

5. 注意点

  1. ThreadLocal本身不存储键值,只是提供了一个在当前线程中找到副本的key,ThreadLocal对象引用地址就是key
  2. 是ThreadLocal包含在Thread中,不是Thread包含在ThreadLocal中

6. 内存泄露问题

  1. ThreadLocalMap: key弱引用,value强引用,无法回收

  2. 显示调用remove导致

2. 关键源码赏析

2.1 ThreadLocal

前置

//创建一个对象,并赋初始值
ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
         @Override
         protected Integer initialValue() {
             return 0;
         }
     };
//获取副本值
threadLocal.get();

源码


    /**
     * 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
     */
	  //获取变量副本值,threadLocal
    public T get() {
      	//获取当前线程
        Thread t = Thread.currentThread();
        //通过当前线程,获取线程局部变量 
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }


	
    /**
     * 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
     */
		//threadLocalMap,this就是ThreadLocal对象引用地址,这里作为key
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }


        /**
         * Construct a new map initially containing (firstKey, firstValue).
         * ThreadLocalMaps are constructed lazily, so we only create
         * one when we have at least one entry to put in it.
         */
        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);
        }

    /**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    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;
    }