我们知道hashmap底层是一个数组+连表的数据结构。
transient Node<K,V>[] table;
数组的长度为什么选择2的幂次。 比如 8或者16,为什么不能为7或者15呢?
答:为了效率, (n - 1) & hash 其中N为16, hash为对象的哈希值,那么会返回【0-15】,正好作为数组的下标,我们知道&效率是最快的。
我们来看一下16的二进制为【0001 0000】 ,15的二进制位【0000 1111】。
【0000 1111】 & hash, &=》俩边为1的为1否则为0,那么不管hash的值是多少,最后的结果肯定<=15,这样就很高效。
那么如果长度是15呢, (n-1)=14 二进制为【0000 1110】。那么只能返回【0,2,4,6,8,14】,显然就不对了。
如果一个数组的长度正好是2的幂次,可以写出一个很高效的轮训算法,并且支持并发访问。
final AtomicInteger idx = new AtomicInteger();
for (int i = 0; i < 1000; i++) {
System.out.println(idx.getAndIncrement() & 16 - 1);
}
如果不是2的幂次,那么可以这么写,同样支持并发访问。
private final AtomicInteger nextServerCyclicCounter = new AtomicInteger(0);
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextServerCyclicCounter.get();
//拿出当前nextServerCyclicCounter的值+1 对 modulo 取模
//计算出的值next肯定小于modulo
int next = (current + 1) % modulo;
//乐观锁设值 如果nextServerCyclicCounter当前值还等于current,则设值成功,否则死循环解决并发问
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}