Java ThreadLocal深入浅出的学习

  

<强>前言

  

ThreadLocal为变量在每个线程中都创建了一个副本,所以每个线程可以访问自己内部的副本变量,不同线程之间不会互相干扰。本文会基于实际场景介绍ThreadLocal如何使用以及内部实现机制。

  

<强>应用场景

  

参数对象的数据需要在多个模块中使用,如果采用参数传递的方式,显然会增加模块之间的耦合性。先看看用ThreadLocal是如何实现模块间共享数据的。

        类参数{   私有静态ThreadLocal,_parameter=new ThreadLocal<的在();   公共静态参数init () {   _parameter。(新参数设置());   }   公共静态参数get () {   _parameter.get ();   }   …省略变量声明   }      
      <李>在模块一个中通过Parameter.init初始化。   <李>在模块B或模块C中通过Parameter.get方法可以获得同一线程中模块一个已经初始化的参数对象。   
  

<>强实现原理

  

从线程线程的角度来看,每个线程内部都会持有一个对ThreadLocalMap实例的引用,ThreadLocalMap实例相当于线程的局部变量空间,存储着线程各自的数据,具体如下:

  

, 深入浅出的学习Java ThreadLocal”> </p>
  <p> <强>条目</强> </p>
  <p>条目继承自WeakReference引用类,是存储线程私有变量的数据结构.ThreadLocal实例作为引,用意味着如果ThreadLocal实例为null,就可以从表中删除对应的条目。</p>
  
  <pre类=   类条目延伸WeakReference      

<强> ThreadLocalMap

  

内部使用餐桌数组存储条目,默认大小INITIAL_CAPACITY(16),先介绍几个参数:

  
      <李>大小:表中元素的数量。   <李>阈值:表大小的2/3,当大小祝辞=阈值时,遍历表并删除键为空的元素,如果删除后大小祝辞=阈值* 3/4时,需要对表进行扩容。   
  

<强> ThreadLocal.set()实现

        公共空集(T值){   线程t=Thread.currentThread ();   ThreadLocalMap地图=getMap (t);   如果(地图!=null)   地图。集(这个值);   其他的   createMap (t值);   }   ThreadLocalMap getMap(线程t) {   返回t.threadLocals;   }      

从上面代码中看出来:

  
      <李>从当前线程线程中获取ThreadLocalMap实例。   <李> ThreadLocal实例和价值封装成条目。   
  

接下去看看条目存表数入组如何实现的:

        私人空集(ThreadLocal<& # 63;比;键,对象值){   条目[]选项卡=表;   int len=tab.length;   int i=键。threadLocalHashCode,(len-1);   (条目e=选项卡(我);e !=零;e=选项卡(i=nextIndex(我,len))) {   ThreadLocal<& # 63;比;k=e.get ();   如果(k==键){   e。值=https://www.yisu.com/zixun/value;   返回;   }   如果(k==null) {   replaceStaleEntry(价值,关键我);   返回;   }   }   选项卡[我]=新条目(键,值);   int深圳=+ +大小;   如果(!深圳cleanSomeSlots(我)& &深圳>=阈值)   重复();   }      

1。通过ThreadLocal的nextHashCode方法生成的哈希值。

        私有静态AtomicInteger nextHashCode=new AtomicInteger ();   私有静态int nextHashCode () {   返回nextHashCode.getAndAdd (HASH_INCREMENT);   }      

从nextHashCode方法可以看的出,ThreadLocal每实例化一次,其散列值就原子增加HASH_INCREMENT。

  

2。通过散列,(len 1)定位到表的位置,假设表中我位置的元素为f。

  

3。如果f !=null,假设f中的引用为凯西:

  
      <李>如果k和当前ThreadLocal实例一致,则修改值值,返回。   <李>如果k为null,说明这个f已经是过期(陈旧的)的元素。调用replaceStaleEntry方法删除表中所有陈旧的元素(即输入的引用为null)并插入新元素,返回。   <李>否则通过nextIndex方法找到下一个元素f,继续进行步骤3。   
  

4。如果f==null,则把条目加入到我表的位置中。

  

5。通过cleanSomeSlots删除陈旧的元素,如果表中没有元素删除,需判断当前情况下是否要进行扩容。

  

Java ThreadLocal深入浅出的学习