InitTable源码详解
时间: 2023-11-14 09:05:05 浏览: 31
ConcurrentHashMap的InitTable方法是用于初始化Segment数组的方法。具体地,InitTable方法会创建一个大小为2的幂次方的Segment数组,并初始化每个Segment。
以下是InitTable方法的源代码及其详细解释:
```java
final void initTable() {
// 如果table为空,则进行初始化
// 其中,sizeCtl表示当前ConcurrentHashMap的状态,如果为0,则表示ConcurrentHashMap还没有被初始化
// 如果为负数,则表示ConcurrentHashMap正在进行扩容操作
// 如果为正数,则表示ConcurrentHashMap还没有进行扩容,sizeCtl的值表示Segment数组的大小
if (table == null) {
// 获取ConcurrentHashMap的初始容量,如果没有指定,则使用默认值
int sc = sizeCtl;
if (sc > 0) {
// 如果sizeCtl大于0,则表示ConcurrentHashMap还没有进行过扩容操作,直接使用sizeCtl作为Segment数组的大小
// 注意:sizeCtl必须是2的幂次方,并且不能小于默认值16
// 因此,这里会将sizeCtl向上取整,同时保证不小于默认值16
// 具体地,这里会将sizeCtl的二进制中最高位的1向右移动一位,从而得到Segment数组的大小
int n = sc >= DEFAULT_CAPACITY ? DEFAULT_CAPACITY : sc;
// 注意:这里的n必须是2的幂次方,因此这里会将n向上取2的幂次方
// 具体地,这里会将n的二进制中最高位的1向右移动一位,然后将低位全部填充为1,从而得到比n大的最小的2的幂次方
int u = (n >>> 1) | n;
u |= u >>> 2;
u |= u >>> 4;
u |= u >>> 8;
u |= u >>> 16;
// 创建大小为u的Segment数组
Segment<K,V>[] tab = (Segment<K,V>[])new Segment<?,?>[u + 1];
// 将Segment数组设置为table
table = tab;
// 计算下一个扩容的阈值,这里的sizeCtl设置为原来的容量大小的0.75倍
// 注意:这里的0.75是根据负载因子计算得到的,表示在达到这个阈值之后,就需要扩容了
// 负载因子是指哈希表中元素的数量和哈希表大小的比值,通常为0.75
sc = u - (u >>> 2);
} else if (sc <= 0) {
// 如果sizeCtl小于等于0,则表示ConcurrentHashMap正在进行扩容操作
sc = DEFAULT_CAPACITY;
} else {
// 如果sizeCtl等于0,则表示ConcurrentHashMap还没有被初始化,使用默认值16作为Segment数组的大小
sc = Integer.highestOneBit(DEFAULT_CAPACITY - 1) << 1;
}
// 设置sizeCtl为sc
sizeCtl = sc;
// 创建大小为sc的Segment数组
Segment<K,V>[] tab = (Segment<K,V>[])new Segment<?,?>[sc];
// 将Segment数组设置为table
table = tab;
// 初始化每个Segment
for (int i = 0; i < tab.length; ++i) {
tab[i] = new Segment<K,V>(loadFactor, (int)(INITIAL_CAPACITY * loadFactor), (int)(MAXIMUM_CAPACITY * loadFactor));
}
}
}
```
总的来说,InitTable方法的作用就是创建大小为2的幂次方的Segment数组,并初始化每个Segment。在创建Segment数组时,会根据当前ConcurrentHashMap的状态来确定Segment数组的大小,同时还会计算下一次扩容的阈值。在初始化每个Segment时,会使用loadFactor、INITIAL_CAPACITY和MAXIMUM_CAPACITY等参数来设置Segment的相关参数。