public V put(K key, V value) {
return putVal(key, value, false);
}
/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
//key和value不能为null
if (key == null || value == null) throw new NullPointerException();
//让hash值的高位也能参与运算
int hash = spread(key.hashCode());
//当前k v封装成node之后,插入桶位之后在桶位中所属的下标位置
//0:表示当前桶位为null
//2:表示当前桶位元素可能已经树化成了红黑树
int binCount = 0;
//自旋
for (Node<K,V>[] tab = table;;) {
//f:桶位的头节点
//n:散列表的长度
//i:key通过寻址计算之后得到的桶位下标
//fh:桶位头结点的哈希值
Node<K,V> f; int n, i, fh;
//如果条件成立,表示table未初始化
if (tab == null || (n = tab.length) == 0)
//多线程竞争初始化数组
tab = initTable();
//如果table已经被初始化
//获取当前桶位的头节点,如果为null,就将封装好的node放入
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
//cas成功,break退出
//cas失败,说明已经有其他线程进入,所以继续自旋
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
//表示当前桶位头节点为FWD节点
//表示map正在扩容过程中
else if ((fh = f.hash) == MOVED)
//当前节点帮助map对象完成数据迁移
tab = helpTransfer(tab, f);
//当前桶位可能是链表节点也有也可能是红黑树节点
else {
//当插入的key存在时,会将旧值赋值给oldVal,然后返回
V oldVal = null;
//给头节点加锁,理论上的 “头节点”
synchronized (f) {
//再次验证当前头节点是否为之前获得的头节点
//避免其他线程将该桶位的头节点修改
//条件成立说明加锁没问题
if (tabAt(tab, i) == f) {
//说明当前桶位是普通链表
if (fh >= 0) {
//1、当前插入的key与链表当中的key都不一致,将key插入到链表末尾,bincount表示链表元素
//2、key已经存在,当前插入操作就为替换,bincount表示冲突位置
binCount = 1;
//迭代循环
for (Node<K,V> e = f;; ++binCount) {
//当前循环节点的key
K ek;
//循环节点的哈希值和待插入元素的哈希值相同
//循环节点的key与待插入节点的key相同
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
//将旧值赋值给oldVal
oldVal = e.val;
//替换,结束
if (!onlyIfAbsent)
e.val = value;
break;
}
//链表中没有相同的key
Node<K,V> pred = e;
//判断下一个节点是否为null,如果是,添加到队尾
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key,
value, null);
break;
}
}
}
//当前桶位是红黑树
else if (f instanceof TreeBin) {
Node<K,V> p;
//bincount<=1有其他含义
binCount = 2;
//如果节点冲突,则返回冲突节点
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
//可能是红黑树也有可能是链表
if (binCount != 0) {
//bincount>=8链表转为红黑树
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
//返回旧值
if (oldVal != null)
return oldVal;
break;
}
}
}
//统计当前table一共有多少数据
//判断是否达到扩容标准
addCount(1L, binCount);
return null;
}
/**
* Initializes table, using the size recorded in sizeCtl.
*/
private final Node<K,V>[] initTable() {
//table引用
//表示临时sizeCTL的值
Node<K,V>[] tab; int sc;
//自旋,条件是散列表未初始化
while ((tab = table) == null || tab.length == 0) {
//-1:当前table正在初始化了
//其他:当前数组正在进行扩容
if ((sc = sizeCtl) < 0)
//大概率为-1,其他线程正在进行初始化
Thread.yield(); // lost initialization race; just spin
//其他情况,==0或者>0
//==0,初始化使用默认常量大小
//>0:如果已经初始化,表示下次扩容时的触发条件
//如果CAS成功,把SIZECTL设置为-1
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;
//n >>> 2?
//sc = n - n*1/4 = 0.75n
//表示下次扩容时的触发条件
sc = n - (n >>> 2);
}
} finally {
//两种情况:
//1、进来的线程成功初始化了数组,所以把sizeCtl当作下一次扩容的阈值
//2、进来的线程没有获取到锁,所以需要将sizeCtl修改为原来的值
sizeCtl = sc;
}
break;
}
}
return tab;
}
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
Node<K,V> c, Node<K,V> v) {
//i表示index,c表示期望值,v表示新值
return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}