final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key ==null || value ==null)throw new NullPointerException();
//先计算出hash 值,然后根据hash 值来计算数组下标
int hash =spread(key.hashCode());
//当前链表上有多少元素
int binCount =0;
//死循环 何时插入成功 何时跳出
for (Node[] tab =table; ; ) {
// table i 位置的节点(当前数组的头节点)
Node f;
int n, i, fh;
//如果数组为空的时候,先进行数组的初始化
if (tab ==null || (n = tab.length) ==0) {
tab = initTable();
//根据hash值计算出在table里面的位置
//tabAt(tab, i = (n - 1) & hash)) 通过hash 值来获取数组的元素。
}else if ((f =tabAt(tab, i = (n -1) & hash)) ==null) {
//通过cas 向第i个位置设置值,cas false 重新走外面的循环
if (casTabAt(tab, i, null, new Node(hash, key, value, null))) {
// no lock when adding to empty bin
break;
}
}else if ((fh = f.hash) ==MOVED) {
//static final int MOVED = -1;
//如果当前的concurrenthashmap 正在进行扩容,帮助hashmap 进行扩容。
tab = helpTransfer(tab, f);
}else {
V oldVal =null;
//当前插入的元素是插入到红黑树,还是插入到链表中。
//对槽的位置进行加锁。(链表的第一个节点进行加锁)
synchronized (f) {
//判断当前链表的头节点是不是还等于f.继续进行循环,获取新的f
if (tabAt(tab, i) == f) {
//fh 证明没有发生过移动。当节点的hash 值是 大于0的时候证明是链表。
if (fh >=0) {
//是链表上面的节点。
binCount =1;
//这个地方对链表进行循环。
for (Node e = f; ; ++binCount) {
K ek;
//如果hash值和key值相同 则修改对应结点的value值
if (e.hash == hash && ((ek = e.key) == key || (ek !=null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent) {
e.val = value;
}
//退出循环
break;
}
Node pred = e;
//如果遍历到了最后一个结点,那么就证明新的节点需要插入 就把它插入在链表尾部(尾插入)
if ((e = e.next) ==null) {
pred.next =new Node(hash, key, value, null);
break;
}
}
}else if (finstanceof TreeBin) {
//节点类型是TreeBin
//如果这个节点是树节点,就按照树的方式插入值
Node p;
binCount =2;
if ((p = ((TreeBin) f).putTreeVal(hash, key, value)) !=null) {
oldVal = p.val;
if (!onlyIfAbsent) {
p.val = value;
}
}
}
}
}
if (binCount !=0) {
//如果链表长度已经达到临界值8 就需要把链表转换为树结构
if (binCount >=TREEIFY_THRESHOLD) {
//对链表进行树化
treeifyBin(tab, i);
}
if (oldVal !=null)
return oldVal;
break;
}
}
}
//扩容条件的判断
addCount(1L, binCount);
return null;
}