ConcurrentHashMap之size()方法
/**
* 计算map中的key-value对总数
* 步骤:
* 1)遍历所有段,计算总的count值sum,计算总的modCount值
* 2)如果有数据的话(modCount!=0),再遍历所有段一遍,计算总的count值check,在这期间只要有一个段的modCount发生了变化,就再重复如上动作两次
* 3)若三次后,还未成功,遍历所有Segment,分别加锁(即建立全局锁),然后计算,最后释放所有锁
*/
public int size() {
final Segment<K, V>[] segments = this.segments;
long sum = 0;//总量
long check = 0;//标志位
int[] mc = new int[segments.length];//存放每个段的modCount
for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
check = 0;
sum = 0;//总的count值
int mcsum = 0;//总的modCount值
for (int i = 0; i < segments.length; ++i) {//遍历所有段
sum += segments[i].count;//计算总的count值
mcsum += mc[i] = segments[i].modCount;//计算总的modCount值
}
if (mcsum != 0) {//有数据的话,再检查一遍
for (int i = 0; i < segments.length; ++i) {
check += segments[i].count;//计算总的count
if (mc[i] != segments[i].modCount) {//只要有一个段发生了变化(在遍历期间发生了增删变化)
check = -1;
break;//跳出所有循环
}
}
}
if (check == sum)//成功
break;
}
if (check != sum) { //以上三次都为成功的话
sum = 0;
//每一个段全部加锁(相当于加了一个全局锁)
for (int i = 0; i < segments.length; ++i)
segments[i].lock();
//进行统计
for (int i = 0; i < segments.length; ++i)
sum += segments[i].count;
//全部解锁
for (int i = 0; i < segments.length; ++i)
segments[i].unlock();
}
if (sum > Integer.MAX_VALUE)
return Integer.MAX_VALUE;
else
return (int) sum;
}
在不加锁的情况下遍历所有Segment,读取每个Segment的count和modCount,并进行统计;
完毕后,再遍历一遍所有Segment,比较modCount,是否发生了变化,若发生了变化,则再重复如上动作两次;
若三次后,还未成功,遍历所有Segment,分别加锁(即建立全局锁),然后计算,最后释放所有锁。
注:以如上的方式,大部分情况下,不需要加锁就可以获取size()