最后我们看看size操作的实现:
Java代码
public int size() {
final Segment
long sum = 0;
long check = 0;
int[] mc = new int[segments.length];
// Try a few times to get accurate count. On failure due to
// continuous async changes in table, resort to locking.
for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
check = 0;
sum = 0;
int mcsum = 0;
for (int i = 0; i < segments.length; ++i) {
sum += segments[i].count;//1.注意这语句
mcsum += mc[i] = segments[i].modCount;//2.还有这一句。
//以上两句是不能调换位置的,还是JSR166 happens-before原则。count之前修改的内容一定会被读取到,jdk 1.5 volatile 关键字的语意增强。
}
if (mcsum != 0) {
for (int i = 0; i < segments.length; ++i) {
check += segments[i].count;
if (mc[i] != segments[i].modCount) {
check = -1; // force retry
break;
}
}
}
if (check == sum)
break;
}
if (check != sum) { // Resort to locking all segments
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;
}
RETRIES_BEFORE_LOCK 的默认值是2,2次循环检测看看modCount的数据是否一致,(modCount的值是只增不减的)一致说明此时没有并发修改。直接返回,否则进行全Segment的加锁计算。
总结:
并发HashMap是Java并发包中名气最大的并发容器。在刚刚发布不久的Java 7 中也有更新。当然仅仅只是版权和类结构上的优化。并没有从算法上更新,所以这里不做展开讨论。并发HashMap中将锁、hash算法和JSR166使用到了极致,是Java中不可多得的财富。只可学习不要轻易模仿。