类的继承关系
Concurrenthashmap继承自Abstractmap实现了map,cloneable,serillizable接口
成员变量
//最大容量
private static final int MAXIMUM_CAPACITY = 1 << 30;
//默认容量 16
private static final int DEFAULT_CAPACITY = 16;
//加载因子
private static final float LOAD_FACTOR = 0.75f;
//转为红黑树判断条件之一 bin数量大于8
static final int TREEIFY_THRESHOLD = 8;
//由树转换成链表的阈值当执行resize操作时
//当桶中bin的数量少于时使用链表来代替树。默认值是6
static final int UNTREEIFY_THRESHOLD = 6;
//如果bin中的数量大于TREEIFY_THRESHOLD,但是capacity小于MIN_TREEIFY_CAPACITY,依然使用链表存储。
此时会进行resize操作,如果capacity大于MIN_TREEIFY_CAPACITY进行树化
static final int MIN_TREEIFY_CAPACITY = 64;
//扩容线程每次最少要迁移16个hash桶
private static final int MIN_TRANSFER_STRIDE = 16;
private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;
//当前位置的Node是一个ForwardingNode节点
static final int MOVED = -1;
//当前位置的Node为一个TreeBin节点
static final int TREEBIN = -2;
//暂存态,即这个节点没有真正初始化完毕
static final int RESERVED = -3;
static final int HASH_BITS = 0x7fffffff;
/** 可用处理器(cpu)数量 */
static final int NCPU=Runtime.getRuntime().availableProcessors();
//桶数组,用来存储Node元素的。默认为null,只在第一次put操作的进行初始化,该数组的长度永远为2的n次方。
transient volatile Node<K,V>[] table;
//默认为null,当不为null,表示当前正在进行扩容操作,这个数组就是扩容之后的数组,长度为原数组的两倍。
private transient volatile Node<K,V>[] nextTable;
//map中元素个数,由于是多线程操作,baseCount记录的不准确,所以要结合counterCells 来使用保证记录的正确性。map的元素个数 = baseCount + 所有的cell的value值。
private transient volatile long baseCount;
- 表初始化和扩容的控制位。
- -1表示当前table数组正在被初始化;
- -N表示有N-1个线程在进行扩容操作;
- 0(默认值)表示当前table还未使用;此时table为null;
- 正整数时,表示table的容量,默认是table大小的0.75倍,(n - (n>>>2))的方式来计算0.75
private transient volatile int sizeCtl;
//用户拆分table的,在扩容的时候
private transient volatile int transferIndex;
// 用来实现cellsBusy锁的,0无锁,1锁;添加map大小使用
private transient volatile int cellsBusy;
// 用来避免伪共享 counterCells用来记录size大小
private transient volatile CounterCell[] counterCells;
3)构造函数
initTable()解析
put()解析
addCount()解析
解析transfer()
解析get()方法
4) put方法分析
public V put(K key, V value) {
return putVal(key, value, false);
}
final V putVal(K key, V value, boolean onlyIfAbsent) {
//检验key,value不能为空
if (key == null || value == null) throw new NullPointerException();
//计算hash值。高16位异或低16位与HASH_BITS
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;😉 {
Node<K,V> f; int n, i, fh;
//如果node数组为空,则初始化table
if (tab == null || (n = tab.length) == 0)
tab = initTable();
//返回(n - 1) & hash=index 位置的元素
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
//通过cas赋值。
if (casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null)))
//这里操作不需要锁,即使multi thread add 那么只会有一个执行成功。casTabAt是原子操作
break;
}
//f.hash == MOVED表示当前数组正在扩容。则进行帮助扩容
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
//注意,这里针对数组的某一个桶加锁
synchronized (f) {
//校验f
if (tabAt(tab, i) == f) {
//fh >= 0得到的节点就是hash值相同的节点组成的链表的头节点
if (fh >= 0) {
binCount = 1;
//遍历数组
for (Node<K,V> e = f;; ++binCount) {
K ek;
//根据hash找到key,判断是否可以覆盖原来的值
//onlyIfAbsent=false覆盖
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, null);
break;
}
}
}
//说明链表是红黑树
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
//把当前元素加入树
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,value)) != null) {
//根据onlyIfAbsent判断是否覆盖
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
if (binCount != 0) {
//binCount >= TREEIFY_THRESHOLD说明要把链表转为红黑树
if (binCount >= TREEIFY_THRESHOLD)
//链表转树
treeifyBin(tab, i);
//老值不为空,返回原来的值
if (oldVal != null)
return oldVal;
break;
}
}
}
//map的容量加1,检查map是否需要扩容
addCount(1L, binCount);
return null;
}
//计算hash值
static final int spread(int h) {
return (h ^ (h >>> 16)) & HASH_BITS;
}