参考地址:https://www.cnblogs.com/zz-ksw/p/12684877.html
threadlocal原理

在线程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);elsecreateMap(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字段,所以不存在链表的情况;
注意:
1、ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。
2、ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过set()来实现的,而是通过每个线程中的new 对象 的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。
通过set()将这个新创建的对象的引用保存到各线程的自己的一个map中,每个线程都有这样一个map,执行get()时,各线程从自己的map中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal实例是作为map的key来使用的。
threadlocal应用场景
场景1:
ThreadLocal 用作保存每个线程独享的对象,为每个线程都创建一个副本,这样每个线程都可以修改自己所拥有的副本, 而不会影响其他线程的副本,确保了线程安全。
场景2:
ThreadLocal 用作每个线程内需要独立保存信息,以便供其他方法更方便地获取该信息的场景。每个线程获取到的信息可能都是不一样的,前面执行的方法保存了信息后,后续方法可以通过ThreadLocal 直接获取到,避免了传参,类似于全局变量的概念。
