ConcurrentHashMap
ConcurrentHashMap
数组 + 链表 +红黑树 的简单梳理
初始化数组长度默认长度16,初始化有指定长度,就会返回指定长度(n)的数组
private final Node<K,V>[] initTable() {
Node<K,V>[] tab; int sc;
while ((tab = table) == null || tab.length == 0) {
if ((sc = sizeCtl) < 0)
Thread.yield(); // lost initialization race; just spin
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;
sc = n - (n >>> 2);
}
} finally {
sizeCtl = sc;
}
break;
}
}
return tab;
}
指定长度数组的计算规则
比指定长度initialCapacity大的最小的2的n次方
tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1))
计算Key的Hash值
int hash = spread(key.hashCode());
添加一个Node节点
i=(n - 1) & hash 数组长度和hash值 转成二进制后进行运算 同为1 就是1,否则为0
如果 数组 i 为空那么就会创建一个Node节点 无锁添加
如果 数组 i 不为空 那么就会为当前Node节点添加子节点 加锁添加
if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,new ConcurrentHashMap.Node<K,V>(hash, key,value, null)))
break;
}
添加一个Node链表的子节点
1、key的去重判断
if (e.hash == hash &&
((ek = e.key) == key || (ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
2、声明一个Node pred将他指向原先存在的Node 对象
ConcurrentHashMap.Node<K,V> pred = e;
3、 找到该Node链表节点下最后一个节点
if ((e = e.next) == null)
4、最后添加链表节点
pred.next = new ConcurrentHashMap.Node<K,V>(hash, key,value, null);
红黑二叉树添加
if (f instanceof ConcurrentHashMap.TreeBin) {
ConcurrentHashMap.Node<K,V> p;
binCount = 2;
if ((p = ((ConcurrentHashMap.TreeBin<K,V>)f).putTreeVal(hash, key,value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
转换成红黑二叉树
如果一个链表下的节点大于等于8 转换成红黑二叉树
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
还没有评论,来说两句吧...