数组初始化方法,这个方法比较简单,就是初始化一个合适大小的数组
sizeCtl这个要单独说一下,如果没搞懂这个属性的意义,可能会被搞晕
这个标志是在Node数组初始化或者扩容的时候的一个控制位标识,负数代表正在进行初始化或者扩容操作
-1 代表正在初始化
-N 代表有N-1有二个线程正在进行扩容操作,这里不是简单的理解成n个线程,sizeCtl就是-N,这块后续在讲扩容的时候会说明0标识Node数组还没有被初始化,正数代表初始化或者下一次扩容的大小
private final Node<K,V>[] initTable() {
Node<K,V>[] tab; int sc;
while ((tab = table) == null || tab.length == 0) {
if ((sc = sizeCtl) < 0)//被其他线程抢占了初始化的操作,则直接让出自己的CPU时间片
Thread.yield(); // lost initialization race; just spin
//通过cas操作,将sizeCtl替换为-1,标识当前线程抢占到了初始化资格
else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
try {
if ((tab = table) == null || tab.length == 0) {
int n = (sc > 0) ? sc : DEFAULT_CAPACITY;//默认初始容量为16
@SuppressWarnings("unchecked")
//初始化数组,长度为16,或者初始化在构造ConcurrentHashMap的时候传入的长度
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
table = tab = nt;//将这个数组赋值给table
sc = n - (n >>> 2); //计算下次扩容的大小,实际就是当前容量的0.75倍,这里使用了右移来计算
}
} finally {
sizeCtl = sc; //设置sizeCtl为sc, 如果默认是16的话,那么这个时候
sc=16*0.75=12
}
break;
}
}
return tab;
}