在putVal最后调用addCount的时候,传递了两个参数,分别是1和binCount(链表长度),看看addCount方法里面做了什么操作
x表示这次需要在表中增加的元素个数,check参数表示是否需要进行扩容检查,大于等于0都需要进行检查
private final void addCount(long x, int check) {
CounterCell[] as; long b, s;
判断counterCells是否为空,
1. 如果为空,就通过cas操作尝试修改baseCount变量,对这个变量进行原子累加操
作(做这个操作的意义是:如果在没有竞争的情况下,仍然采用baseCount来记录元素个
数)
2. 如果cas失败说明存在竞争,这个时候不能再采用baseCount来累加,而是通过
CounterCell来记录
if ((as = counterCells) != null || !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)){
CounterCell a; long v; int m;
boolean uncontended = true;//是否冲突标识,默认为没有冲突
这里有几个判断
1. 计数表为空则直接调用fullAddCount
2. 从计数表中随机取出一个数组的位置为空,直接调用fullAddCount
3. 通过CAS修改CounterCell随机位置的值,如果修改失败说明出现并发情况(这里又
用到了一种巧妙的方法),调用fullAndCount
Random在线程并发的时候会有性能问题以及可能会产生相同的随机
数,ThreadLocalRandom.getProbe可以解决这个问题,并且性能要比Random高
if (as == null || (m = as.length - 1) < 0 || (a = as[ThreadLocalRandom.getProbe() & m]) == null || !(uncontended = U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
fullAddCount(x, uncontended);//执行fullAddCount方法
return;
}
if (check <= 1)//链表长度小于等于1,不需要考虑扩容
return;
s = sumCount();//统计ConcurrentHashMap元素个数
}
//….
}