ConcurrentHashMap的构造
<代码> ConcurrentHashMap,采用了一种“懒加载”的模式,只有到首次插入键值对的时候,才会真正的去初始化表数组。代码>
构造方法:
1,空构造函数,默认桶大小16
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)类和方法分析)