final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
Node<K,V> c, Node<K,V> v) {
return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}
理解标红的地方:不断循环计算table(散列表)的每个桶位(slot)的散列值i ,直到找到tab[i] 为空的桶位,casTabAt将put(增加)的节点Node 放到空仓(empty bin)中,如果在put 的过程中,别的线程更改了tab[i],导致tab[i] 不为空,那么casTabAt返回false,继续循环找tab[i]== null的桶位。整个put 过程没加锁,利用table 是volatile 的特性,保证在多线程并发更新的过程中table 对所有线程是一致的,Unsafe 可以直接操作内存中的对象。