ConcurrentHashMap中并发级别,桶内hash表的长度,扩容门槛的确定
来源:互联网 发布:苏沉船知乎 编辑:程序博客网 时间:2024/05/22 12:49
ConcurrentHashMap中sigment数量,sigment中hash表的长度,以及加载因子的确定。
分析一下下面的构造函数参数 initialCapacity
是我们指定的map的初始容量大小,但是map初始完成后的容量并不一定等于该值。 loadFactor
用来控制每个桶内的扩容的门槛threshold
桶内元素大于该值,要扩容在hashrehash()
concurrencyLevel
并发的级别,用来间接指定map中通的数量。
上面参数的具体使用,看一下下面的具体代码的注释部分。
(1)static final int MAXIMUM_CAPACITY = 1 << 30; (2)static final int DEFAULT_CONCURRENCY_LEVEL = 16; (3)static final int MAX_SEGMENTS = 1 << 16; // slightly conservative public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) { //合法性检查loadFactor 装填因子是小于1大于0的。threshold是根据hash表的长度*loadFactor计算所得 if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) throw new IllegalArgumentException(); //并发量不得大于MAX_SEGMENTS,见函数上面的值(3) if (concurrencyLevel > MAX_SEGMENTS) concurrencyLevel = MAX_SEGMENTS; // Find power-of-two sizes best matching arguments int sshift = 0; int ssize = 1; //桶的数量是比我们指定的并发数量concurrencyLevel大或者相等的最小的2的n次幂。 while (ssize < concurrencyLevel) { ++sshift; ssize <<= 1; } //通过元素的hash值定位所在桶时用到的掩码,结合下面segmentFor函数,可以得至,在定位桶时,是使用了,hash值得高sshift位来计算的。 segmentShift = 32 - sshift; segmentMask = ssize - 1; //初始化桶 this.segments = Segment.newArray(ssize); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; //首先根据我们指定的初始化容量和上面计算的桶的数量计算一个大概的hash表的长度 int c = initialCapacity / ssize; //这里需要重新算一下,找到一个比initialCapacity大获相等的最小的一个ssize的倍数 if (c * ssize < initialCapacity) ++c; int cap = 1; //上面我们找到的c只是一个辅助我们确定hash长度的数值,下面我们通过移位找到比c大的最小的2 的n次幂 while (cap < c) cap <<= 1; for (int i = 0; i < this.segments.length; ++i) this.segments[i] = new Segment<K,V>(cap, loadFactor); } final Segment<K,V> segmentFor(int hash) { return segments[(hash >>> segmentShift) & segmentMask]; }
上面有提到,为什么在计算桶的时候,要用hash >>> segmentShift
来定位,个人理解是,如果采用低位,很大程度上吧地位hash值相同或者类似的都会放到一个桶中,这样会造成entry数组中的某个元素的链表特别长,引起hash冲突。
下面参数使用的举个例子
例如,我们指定initialCapacity是31,loadFactor是0.75,concurrencyLevel 是17。我们看一下具体的桶大小和hash表的大小,以及扩容门槛的具体值。
桶的数量:大于concurrencyLevel的最小的2的n次幂,这里是,32。
hash表的长度:首先计算c,c=31/32=0,比31大且是32的倍数的,那么就是1。
扩容门槛:2*0.75 = 1.5,取整0。
这样我们放入一个元素后就会引起hash表的扩容,这里我们要注意,再次扩容时,桶的数量是固定的,扩大的是桶内的hash表。这里扩容时2倍。hashmap 2倍。hashtable 2倍+1。
下面验证一下我们的结论。通过加入断点,我们看一下。
没问题,桶的数量是32
hash表的长度也是1,加载因子0.75
按说put第一个元素是就要扩容,但是却没有。看一下具体的扩容函数,我们发现,判断是否要扩容的时候,主要是下面一段代码,其中count是当前hash表中的元素数量,初始为0。我们从上面得知threshold也为0,c++ > threshold
却没有成立,这里的情况和之前分析的i=i++有点类似,可以看这篇文章。其实正真的意思是,只有当前hash表中元素已经大于或等于threshold的了,在放入元素才会扩容在hash,如果当前数量为threshold-1,我们放入一个元素后数量为threshold,照样不会引起扩容。
int c = count; if (c++ > threshold) // ensure capacity rehash();
//默认初始容量static final int DEFAULT_INITIAL_CAPACITY = 16;//默认加载因子static final float DEFAULT_LOAD_FACTOR = 0.75f;//默认的并发级别static final int DEFAULT_CONCURRENCY_LEVEL = 16;
默认初始化之后,桶的数量是16,桶内hash表的数量是1,加载因子是0。75。默认的参数扩容比较频繁,我们可以根据自己的要求初始化这三个参数。
- ConcurrentHashMap中并发级别,桶内hash表的长度,扩容门槛的确定
- char *的地址长度的确定
- Nginx对长连接的处理及HTTP协议中body长度的确定
- 矩形内点的确定
- HTTP实体长度的确定规则
- java-并发集合-并发hash表 ConcurrentHashMap 演示
- svm中gamma的确定
- java 并发线程个数的确定
- CNC加工中刀具的选择与切削用量的确定
- hadoop中map数量的确定及host的选择
- Hash表的扩容(转载)
- Java中高效的并发容器----ConcurrentHashMap
- 一种可衡量的确定MySQL前缀索引长度方法
- 调查研究中样本量的确定
- 聚类分析中分类数的确定问题
- WINCE注册表中IClass值的确定
- mapreduce中map个数的确定
- mapreduce中map个数的确定
- C#读取XML文档实例
- Java向下转型的意义
- hdu2159 完全背包
- 3299 (入门水题 套公式)
- 深度学习在健康医疗领域的应用综述
- ConcurrentHashMap中并发级别,桶内hash表的长度,扩容门槛的确定
- String中Comparable的compareTo使用及释义
- 6 Difference Between HashMap And HashTable
- 图片格式转换-在线
- 在 ASP.NET MVC Web 应用程序中输出 RSS格式数据
- R语言规范化 scale()
- PopupWindow 可以指定弹窗的位置以及背景色等特性
- java中的数组
- Broadcast