static final class TreeBin<K,V> extends Node<K,V> {}
作为 treebin 的头节点, 存储 root 和 first
链表过长,O(1)-->O(n)链表过长使用红黑树,O(n)-->O(logn)
红黑树使用条件
先扩容,哈希表长度到64,当前某个节点链表长度大于8,将链表转换为红黑树;
链表长度小于6时将红黑树转换为链表
static final class TreeNode<K,V> extends Node<K,V> {}
作为 treebin 的节点, 存储 parent, left, right
1.2 构造器分析
public ConcurrentHashMap(int initialCapacity,
float loadFactor, int concurrencyLevel) {
if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
throw new IllegalArgumentException();
if (initialCapacity < concurrencyLevel) // 如果初始容量的值小于并发度
initialCapacity = concurrencyLevel; // 将初始容量的值设置为并发度
long size = (long)(1.0 + (long)initialCapacity / loadFactor);
int cap = (size >= (long)MAXIMUM_CAPACITY) ?
MAXIMUM_CAPACITY : tableSizeFor((int)size);
this.sizeCtl = cap;
}
//指定容量:容量为大于当前值的2的幂,例如构造器传入3,初始容量返回4
private static final int tableSizeFor(int c) {//c=3(11) 说明:括号内为二进制
int n = c - 1;//n=2(10)
n |= n >>> 1;// n>>>1=1(01),n|n>>>1 = 3(11)
n |= n >>> 2;// n>>>2=0(00),n|n>>>2 = 3(11)
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
//返回4,保证了2的幂数
//扩容时为原容量的2倍
}
1.3 put流程分析
final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
//如果key或者value其中一个null,就报空指针异常
int hash = spread(key.hashCode());
// spread:(h ^ (h >>> 16)) & HASH_BITS
// HASH_BITS:正常节点哈希的可用位,会综合高位低位, 具有更好的 hash 性
// 保障正整数(负数也其他用处)
// MOVED = -1; // hash for forwarding nodes
// TREEBIN = -2; // hash for roots of trees
// RESERVED = -3; // hash for transient reservations
int binCount = 0;
for (ConcurrentHashMap.Node<K,V>[] tab = table;;) {
ConcurrentHashMap.Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
// 初始化创建hash表,
// 若有一个线程正在创建table,其它线程会在 while() 循环中 yield 直至hash表的创建
// U.compareAndSwapInt(this, SIZECTL, sc, -1)
// 使用CAS保证只有一个线程进入条件,将sizeCtl置-1,进行table的创建
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
// 要创建链表头节点
// 获取 Node[] 中第 i 个 Node(链表头),如果为空,说明可以插入
// U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE)