首先把那些恶心的变量解释一下
变量名称 | 含义 |
bincount | table里目标索引链表的元素个数 |
f | table里目标索引对应链表的头结点 |
n | table的长度 |
i | 目标索引 |
fh | 头结点f的哈希值 |
tab | table数组的副本 |
final V putVal(K key, V value, boolean onlyIfAbsent) {
//1、判断key是否为空
if (key == null || value == null) throw new NullPointerException();
//2、计算哈希值
int hash = spread(key.hashCode());
int binCount = 0;
//3、得到table的数组
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
//4.如果table数组为空,则初始化table
if (tab == null || (n = tab.length) == 0)
tab = initTable();
//5.如果对应key的哈希值上对应table数组下标的位置没有node,则通过cas操作创建一个node放入table中,然后putval出栈
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
}
//6、如果table正在扩容,则得到扩容后的table,然后再重新开始一个循环
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
//7.到这里说明找到了key hash后对应的table,并且table上有其他node的存在
V oldVal = null;
//8、把这个找到的node加上同步锁,防止并发出现的问题,如果其他key put进来的时候也对应这个tab则堵塞在这里
synchronized (f) {
//9.再次用cas确认索引i上的table为我们找到的node,如果不是的话则这个node被修改,直接释放锁进入下一个循环
if (tabAt(tab, i) == f) {
//10.如果目标table的第一个node的哈希值大于等于0,则是链式结构,走链表查找,反之走红黑树查找
if (fh >= 0) {
//11.标志bincount为1,因为在该table上至少有一个node节点
binCount = 1;
//12.循环链表
for (Node<K,V> e = f;; ++binCount) {
K ek;
//13.如果遍历元素的哈希值与需要插入目标key的哈希值相同,并且值也相同,则插入的是重复key的元素
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
//14.如果onlyIfAbsent为false的话,则替换为新value,否则不修改(一般传false)
if (!onlyIfAbsent)
e.val = value;
//15.break循环
break;
}
//16.循环直到最后一个node节点的key都不是我们想要插入的key
Node<K,V> pred = e;
if ((e = e.next) == null) {
//在尾部添加一个新节点,break循环
pred.next = new Node<K,V>(hash, key,
value, null);
break;
}
}
}
//17.该节点属于红黑树的子节点,进行树操作
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
//18.如果node节点不为0
if (binCount != 0) {
//19.如果node大于或者等于8,则转为红黑树
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
//20.返回原来key对应的旧值
if (oldVal != null)
return oldVal;
break;
}
}
}
//20.进行扩容判断
addCount(1L, binCount);
return null;
}
如有不正确的地方,欢迎指出