本篇是自己对ConcurrentHashMap某些源码的一些分析。
put方法
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) {
//不允许插入null键
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; K fk; V fv;
//Node数组为空则进行数组初始化
if (tab == null || (n = tab.length) == 0)
tab = initTable();
//如果数组对应位置没有值,就进行cas添加,失败就进行break,注意求位置用了与操作
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
break; // no lock when adding to empty bin
}
//如果此位置元素已经存在,且处于被移动元素状态,就协助扩容
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
//不进入此块。因为put方法中onlyIfAbsent传入为false
else if (onlyIfAbsent // check first node without acquiring lock
&& fh == hash
&& ((fk = f.key) == key || (fk != null && key.equals(fk)))
&& (fv = f.val) != null)
return fv;
//发生hash碰撞,就锁注此位置的链表或红黑树
else {
V oldVal = null;
synchronized (f) {
//如果此位置是 链表 的头结点。
//f是此位置头结点,i是通过hash求出的元素位置,求法见第一个else if那里的条件
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
//若存在此节点,就更新value值
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
//如果到了最后一个节点仍然找不到相同的,就添加在链表后面
Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key, value);
break;
}
}
}
//如果此位置是 红黑树 的头结点,进行添加操作
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;
}
}
//若f是保留节点,就抛出更新异常
else if (f instanceof ReservationNode)
throw new IllegalStateException("Recursive update");
}
}
//若链表长度到达临界值,就转为红黑树
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
addCount(1L, binCount);
return null;
}
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/19387.html