多线程(十五,ConcurrentHashMap原理(2)类和方法分析)

  

ConcurrentHashMap的构造

  
 <代码> ConcurrentHashMap,采用了一种“懒加载”的模式,只有到首次插入键值对的时候,才会真正的去初始化表数组。 
  

构造方法:

  

1,空构造函数,默认桶大小16
多线程(十五,ConcurrentHashMap原理(2)类和方法分析)
2,指定桶初始容量的构造器,必须是2次幂值

  
 <代码>/* *
  *指定表初始容量的构造器。
  * tableSizeFor会返回大于入参(initialCapacity + (initialCapacity祝辞祝辞祝辞1)+ 1)的最小2次幂值
  */公共ConcurrentHashMap (int initialCapacity) {
  如果(initialCapacity & lt;0)
  把新IllegalArgumentException ();
  
  int帽=((initialCapacity祝辞=(MAXIMUM_CAPACITY祝辞祝辞祝辞1))?MAXIMUM_CAPACITY:
  tableSizeFor (initialCapacity + (initialCapacity祝辞祝辞祝辞1)+ 1));
  
  这一点。sizeCtl=帽;
  } 
  

3,根据已有地图的构造
4,指定表初始容量和负载因子的构造器
5,指定表初始容量,负载因子,并发级别的构造器

  

常用字段介绍

  
 <代码>/* *
  *最大容量。
  */私有静态最终int MAXIMUM_CAPACITY=1 & lt; & lt;30;/* *
  *默认初始容量
  */私有静态最终int DEFAULT_CAPACITY=16;/* *
  *负载因子,为了兼容JDK1.8以前的版本而保留。
  * JDK1.8中的ConcurrentHashMap的负载因子恒定为0.75
  */私有静态最终浮LOAD_FACTOR f=0.75;/* *
  *链表转树的阈值,即链接结点数大于8时,链表转换为树。
  */静态最终int TREEIFY_THRESHOLD=8;/* *
  *树转链表的阈值,即树结点树小于6时,树转换为链表。
  */静态最终int UNTREEIFY_THRESHOLD=6;/* *
  *在链表转变成树之前,还会有一次判断:
  *即只有桶大小数量大于MIN_TREEIFY_CAPACITY,才会发生转换。
  *这是为了避免在表建立初期,多个键值对恰好被放入了同一个链表中而导致不必要的转化。
  */静态最终int MIN_TREEIFY_CAPACITY=64;/* *
  *在树转变成链表之前,还会有一次判断:
  *即只有桶的数量小于MIN_TRANSFER_STRIDE,才会发生转换。
  */私有静态最终int MIN_TRANSFER_STRIDE=16;/* *
  *用于在扩容时生成唯一的随机数。
  */私有静态int RESIZE_STAMP_BITS=16;/* *
  *可同时进行扩容操作的最大线程数。
  */私有静态最终int MAX_RESIZERS=(1 & lt; & lt;(32 - RESIZE_STAMP_BITS)) - 1;
  
  静态最终int移动=1;//标识ForwardingNode结点
  静态最终int TREEBIN=2;//标识红黑树的根结点
  静态最终int保留=3;//标识ReservationNode结点()
  静态最终int HASH_BITS=0 x7fffffff;//可用位正常节点的哈希/* *
  * CPU核心数,扩容时使用
  */静态最终int NCPU=Runtime.getRuntime () .availableProcessors ();/* *
  *节点数组,标识整个地图,首次插入元素时创建,大小总是2的幂次。
  */瞬态波动Node[]表;/* *
  *扩容后的新节点数组,只有在扩容时才非空。
  */私人瞬态波动Node [] nextTable;/* *
  *控制表的初始化和扩容。
  * 0:初始默认值
  * 1:有线程正在进行表的初始化
  *在0:表初始化时使用的容量,或初始化/扩容完成后的阈值
  * (1 + nThreads):记录正在执行扩容任务的线程数
  */私人瞬态波动int sizeCtl;/* *
  *扩容时需要用到的一个下标变量。
  */私人瞬态波动int transferIndex;/* *
  *计数基值,当没有线程竞争时,计数将加到该变量上。类似于LongAdder的基地变量
  */私人瞬态波动长baseCount;/* *
  *计数数组,出现并发冲突时使用。类似于LongAdder的细胞数组
  */私人瞬态波动CounterCell [] counterCells;/* *
  *自旋标识位,用于CounterCell[]扩容时使用。类似于LongAdder的cellsBusy变量
  */私人瞬态波动int cellsBusy;
   
  

把方法

  
 <代码>/* *
  *插入键值对,& lt; K, V>均不能为null。
  */公共V把(K键,V值){
  返回putVal(价值,关键错误);
  } 
  
 <代码>/* *
  *实际的插入操作
  *
  * @param onlyIfAbsent真的:仅当关键不存在时,才插入
  */最后V putVal (K键,V值,布尔onlyIfAbsent) {
  如果(关键==null | |值=https://www.yisu.com/zixun/=null)抛出NullPointerException ();
  int散列=传播(key.hashCode ());//再次计算的哈希值/* *
  *使用链表保存时,binCount记录表[我]这个桶中所保存的节点数;
  *使用红黑树保存时,binCount==2,保证放后更改计数值时能够进行扩容检查,同时不触发红黑树化操作
  */int binCount=0;
  
  (节点的

多线程(十五,ConcurrentHashMap原理(2)类和方法分析)