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

threadlocal原理

image.png
在线程A中初始化了一个ThreadLocal对象local,并set了一个值test,同时在线程A中通过get可拿到之前设置的值,但是如果在线程B中,拿到的将是一个null
这是如何实现的呢?之前说过,ThreadLocal保证了各个线程的数据互不干扰
看看set(T value)和get()方法的源码

  1. // 返回当前线程该线程局部变量副本中的值
  2. public T get() {
  3. Thread t = Thread.currentThread();
  4. ThreadLocalMap map = getMap(t);
  5. if (map != null) {
  6. ThreadLocalMap.Entry e = map.getEntry(this);
  7. if (e != null) {
  8. @SuppressWarnings("unchecked")
  9. T result = (T)e.value;
  10. return result;
  11. }
  12. }
  13. return setInitialValue();
  14. }
  15. /**
  16. *设置此线程局部变量的当前线程的副本到指定的值
  17. *大多数的子类都不需要重写此方法
  18. */
  19. public void set(T value) {
  20. Thread t = Thread.currentThread();
  21. ThreadLocalMap map = getMap(t);
  22. if (map != null)
  23. map.set(this, value);
  24. else
  25. createMap(t, value);}
  26. /**
  27. * Get the map associated with a ThreadLocal. Overridden in
  28. * InheritableThreadLocal.
  29. *
  30. * @param t the current thread
  31. * @return the map
  32. */
  33. ThreadLocalMap getMap(Thread t) {
  34. return t.threadLocals;
  35. }

可以发现,每个线程中都有一个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字段,所以不存在链表的情况;
image.png

注意:

1、ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。
2、ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过set()来实现的,而是通过每个线程中的new 对象 的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。
通过set()将这个新创建的对象的引用保存到各线程的自己的一个map中,每个线程都有这样一个map,执行get()时,各线程从自己的map中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal实例是作为map的key来使用的。

threadlocal应用场景

场景1:

ThreadLocal 用作保存每个线程独享的对象,为每个线程都创建一个副本,这样每个线程都可以修改自己所拥有的副本, 而不会影响其他线程的副本,确保了线程安全。

场景2:

ThreadLocal 用作每个线程内需要独立保存信息,以便供其他方法更方便地获取该信息的场景。每个线程获取到的信息可能都是不一样的,前面执行的方法保存了信息后,后续方法可以通过ThreadLocal 直接获取到,避免了传参,类似于全局变量的概念。