ConcurrentHashMap源码阅读#initTable
2020-03-23 本文已影响0人
丫头可乐
private final Node<K,V>[] initTable() {
Node<K,V>[] tab;
int sc;
//如果tab一直为null,就一直进行循环,直到当前线程获取到Node数组
while ((tab = table) == null || tab.length == 0) {
//sizeCtl为-1时,表示有其他线程正在进行初始化
if ((sc = sizeCtl) < 0)
//这里yield()方法会告知调度器说我要让出CPU,重新恢复到就绪状态。
//至于能不能成功让出cpu,也不一定。
//如果能成功让出,当前线程恢复到ready状态,在等待再次运行的过程当中。
//其他的线程可能已经完成初始化了。这样就可以直接返回tab。
//如果没有让出,那就继续进行while循环,等待其他线程完成初始化工作。
Thread.yield(); // lost initialization race; just spin
//这里使用CAS原子操作对sizeCtl进行修改。将原来的值,改成-1。这里就说明了,如果sizeCtl被成功修改成了-1,就表明有一个线程正在进行初始化。其他的线程再进来的时候,拿到sizeCtl=-1。然后yield出CPU。
else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
try {
/**
*设有两个线程t1,t2都在进行初始化操作。
*这个时候,t1已经完成了初始化,这个时候sizeCtl根据下面的逻辑应该是12。
*而这时候,t2刚刚进入到while循环中,这时候,会重新给sizeCtl赋值成-1。
*赋值成功后,如果没有空判断,则又会重新初始化一遍。
*/
if ((tab = table) == null || tab.length == 0) {
int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
@SuppressWarnings("unchecked")
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
table = tab = nt;
sc = n - (n >>> 2);
}
} finally {
/**
*After initialization, holds the next element count value upon which to resize the table.
*
*根据这句话,我们可以得知,在完成初始化后,sizeCtl的值被设置称为0.75*capacity
*/
sizeCtl = sc;
}
break;
}
}
return tab;
}