I'm learning the java source code, when i reading the ConcurrentHashMap source code, i'm confused with the initTable() method, why check (tab = table) == null || tab.length == 0
twice, first in the while()
, then in the if()
. I can't imagine in what situation need the second check.
I think maybe it's because the JVM reorder the code, put sizeCtl = sc;
in front of Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
. It's just my guess, I don't know is it right.
Can some one explain it, thanks a lot.
private final Node<K,V>[] initTable() {
Node<K,V>[] tab; int sc;
while ((tab = table) == null || tab.length == 0) {
if ((sc = sizeCtl) < 0)
Thread.yield(); // lost initialization race; just spin
else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
try {
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 {
sizeCtl = sc;
}
break;
}
}
return tab;
}
Multiple threads may compete to do this (see "initialization race" comment).
To paraphrase the code:
while(uninitialized) {
acquire_lock(); //compareAndSwapInt...
if(uninitialized) {
do_init();
}
}
The outer check is a cheap "unlocked" test. The inner one is in case someone else already succeeded between while
and compareAndSwapInt
.