ConcurrentHashMap核心原理,彻底给整明白了( 四 )

这是一个有参数的构造方法 。 如果你对未来存储的数据量有预估 , 我们可以指定哈希表的大小 , 避免频繁的扩容操作 。 tableSizeFor 这个方法确保了哈希表的大小永远都是 2 的 n 次方 。
注意这里传入的参数不是 initialCapacity , 而是 initialCapacity 的 1.5 倍 + 1 。 这样做是为了保证在默认 75% 的负载因子下 , 能够足够容纳 initialCapacity 数量的元素 。
ConcurrentHashMap (int initialCapacity) 构造函数总结下:
1、构造函数中并不会初始化哈希表;
2、构造函数中仅设置哈希表大小的变量 sizeCtl;
3、initialCapacity 并不是哈希表大小;
4、哈希表大小为 initialCapacity*1.5+1 后 , 向上取最小的 2 的 n 次方 。 如果超过最大容量一半 , 那么就是最大容量 。
tableSizeFor 是如何实现向上取得最接近入参 2 的 n 次方的 。 下面我们来看 tableSizeFor 源代码:
private static final int tableSizeFor(int c) {int n = c - 1;n |= n >>> 1;n |= n >>> 2;n |= n >>> 4;n |= n >>> 8;n |= n >>> 16;return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;}复制代码依旧是二进制按位操作 , 这样一顿操作后 , 得到的数值就是大于 c 的最小 2 的 n 次 。 我们推演下过程 , 假设 c 是 9:
1、int n = 9 - 1n=82、n |= n >>> 1n=1000n >>> 1=0100两个值按位或后n=11003、n |= n >>> 2n=1100n >>> 2=0011n=1111复制代码到这里可以看出规律来了 。 如果 c 足够大 , 使得 n 很大 , 那么运算到 n |= n >>> 16 时 , n 的 32 位都为 1 。
总结一下这一段逻辑 , 其实就是把 n 有数值的 bit 位全部置为 1 。 这样就得到了一个肯定大于等于 n 的值 。 我们再看最后一行代码 , 最终返回的是 n+1 , 那么一个所有位都是 1 的二进制数字 , +1 后得到的就是一个 2 的 n 次方数值 。