ThreadLocal原理及使用场景大揭秘

是什么ThreadLocal从名字上看好像是一个Thread , 其实并不是 , 它是Therad的局部变量的维护类 。作用是让变量私有化(为每个Thread提供变量的副本) , 以此来实现线程间变量的隔离 。比如有一个变量count , 在多线程并发时操作count++会出现线程安全问题 。但是通过ThreadLocal count , 就可以为每个线程创建只属于当前线程的count副本 , 各自操作各自的副本 , 不会影响到其他线程 。我们先有个概念 , 具体还是看源码(JDK1.8) 。

ThreadLocal原理及使用场景大揭秘

文章插图
 
原理源码简单用法
public static void main(String[] args) {        ThreadLocal<String> a = new ThreadLocal<String>();        a.set("1");        a.set("2");        System.out.println(a.get());    }//输出结果是2 。貌似“1”被覆盖了 。先看一下set(T value)方法 。
  /**     * Sets the current thread's copy of this thread-local variable     * to the specified value.  Most subclasses will have no need to     * override this method, relying solely on the {@link #initialValue}     * method to set the values of thread-locals.     *     * @param value the value to be stored in the current thread's copy of     *        this thread-local.     *     */    public void set(T value) {        //当前线程        Thread t = Thread.currentThread();        //获取ThreadLocalMap        ThreadLocalMap map = getMap(t);        //map为空就创建 , 不为空就set        if (map != null)            map.set(this, value);        else            createMap(t, value);    }     //给t.threadLocals赋值成ThreadLocalMap实例 。    void createMap(Thread t, T firstValue) {        t.threadLocals = new ThreadLocalMap(this, firstValue);    }    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);   }   /**   * Set the resize threshold to maintain at worst a 2/3 load factor.   */   private void setThreshold(int len) {       threshold = len * 2 / 3;   }      /* 当前线程对于的ThreadLocalMap实例 , 在ThreadL类中*/   ThreadLocal.ThreadLocalMap threadLocals = null;这段代码逻辑比较简单 , 主要看ThreadLocalMap , 它是TreadLocal的内部类 , 虽然没有实现Map接口 , 但看它的几个主要属性:Entry[] table、size、threshold、INITIAL_CAPACITY , 和JAVA.util.HashMap极其类似 。关于这些属性更详尽的解释可以看一下这篇深入讲解HashMap的工作原理。class注释中也提到它是一个为存放本地线程值而定制的hash map 。它的key就是ThreadLocal当前实例this , 值就是set的参数值 。既然是hash map , 就有可能出现hash冲突的问题 , 再复习一下解决hash冲突的常见方法


推荐阅读