threadlocal原理及常用应用场景

1.深入解析ThreadLocal类

ThreadLocal类提供的几个方法:

  1. public T get() { }  
  2. public void set(T value) { }  
  3. public void remove() { }  
  4. protected T initialValue() { }

  get()方法是用来获取ThreadLocal在当前线程中保存的变量副本,set()用来设置当前线程中变量的副本,remove()用来移除当前线程中变量的副本,initialValue()是一个protected方法,一般是用来在使用时进行重写的,它是一个延迟加载方法

  

  一个以ThreadLocal对象为键、任意对象为值的存储结构。
  是一个数据结构,有点像HashMap,可以保存"key : value"键值对,但是一个ThreadLocal只能保存一个,并且各个线程的数据互不干扰。
  该结构被附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值。
 
  
ThreadLocal<String> local = new ThreadLocal();
local.set("test");
String demo = local.get();

在线程A中初始化了一个ThreadLocal对象local,并set了一个值test,同时在线程A中通过get可拿到之前设置的值,但是如果在线程B中,拿到的将是一个null

这是如何实现的呢?之前说过,ThreadLocal保证了各个线程的数据互不干扰
  看看set(T value)和get()方法的源码

  

    // 返回当前线程该线程局部变量副本中的值
        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();
        }
       /**
         *设置此线程局部变量的当前线程的副本到指定的值
         *大多数的子类都不需要重写此方法
         */
        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);}
   /**
     * 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;
    }

 


可以发现,每个线程中都有一个ThreadLocalMap数据结构
执行set时,其值是保存在当前线程的threadLocals变量中,执行get时,从当前线程的threadLocals变量获取

所以在线程A中set的值,对线程B来说是摸不到的,而且在线程B中重新set的话,也不会影响到线程A中的值,保证了线程之间不会相互干扰


 

ThreadLocalMap是一个类似HashMap的数据结构,但是在ThreadLocal中,并没实现Map接口;

在ThreadLoalMap中,也是初始化一个大小为16的Entry数组table,Entry节点对象用来保存每一个key-value键值对,这里的key永远都是ThreadLocal对象,通过ThreadLocal对象的set方法,结果把ThreadLocal对象自己当做key;

ThreadLoalMap的Entry是继承WeakReference,和HashMap很大的区别是,Entry中没有next字段,所以不存在链表的情况;

 

 2.需要注意:

ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。

另外,说ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过set()来实现的,而是通过每个线程中的new 对象 的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。
通过set()将这个新创建的对象的引用保存到各线程的自己的一个map中,每个线程都有这样一个map,执行get()时,各线程从自己的map中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal实例是作为map的key来使用的。










 

posted @ 2018-01-08 14:18  精细匠人  阅读(1248)  评论(0编辑  收藏  举报