ConcurrentHashMap的该构造方法

public ConcurrentHashMap(int initialCapacity) 
    // 校验初始容量不能小于0
    if (initialCapacity < 0)
        throw new IllegalArgumentException();
    int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
               MAXIMUM_CAPACITY :
               tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
    this.sizeCtl = cap;
}

如果initialCapacity大于最大容量的一半时,就取最大容量。

// 1无符号左移30位,也就是二进制1后面跟着30个0。Java中int有32位,第一位为符号位。所以1<<30为int类型中, 最大且是2的n(正整数)次幂的数。
private static final int MAXIMUM_CAPACITY = 1 << 30;

否则执行tableSizeFor()方法。

二、tableSizeFor()方法

/**
 * 根据容量参数,返回一个2的n次幂的table长度。
 */
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;
}

 先看一下tableSizeFor()的输入与输出 

public static void main(String[] args) {
    System.out.println(tableSizeFor(1));
    System.out.println(tableSizeFor(5));
    System.out.println(tableSizeFor(25));
    System.out.println(tableSizeFor(125));
    System.out.println(tableSizeFor(625));
}

输出:
1
8
32
128
1024
>>>表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0

通过输出可以大致猜到tableSizeFor的作用是返回一个大于输入参数且最小的为2的n次幂的数。

我们再来看看是怎么做到的。

当输入为25的时候,n等于24,转成二进制为11000,右移1位为01100,

将11000与01100进行或("|")操作,

11000

01100

11100

得到11100

接下来右移两位得111,

11100

00111

得到11111

再进行右移4位得1,

11111

00001

得到11111

接下来操作n右移8位得0

11111

00000

得到11111

右移16位得0。

11111

00000

得到11111

最后返回的时候,返回n+1,也就是100000,转换十进制运算为:2的5次方=十进制为32。按照这种逻辑得到2的n次幂的数。

二进制与、或、异或运算

再来看一个例子,当n=1<<30的时候:

01 00000 00000 00000 00000 00000 00000 (n)   
01 10000 00000 00000 00000 00000 00000 (n |= n >>> 1)    
01 11100 00000 00000 00000 00000 00000 (n |= n >>> 2)    
01 11111 11000 00000 00000 00000 00000 (n |= n >>> 4)    
01 11111 11111 11111 00000 00000 00000 (n |= n >>> 8)    
01 11111 11111 11111 11111 11111 11111 (n |= n >>> 16)    

由于int类型为32位,所有即使除符号为之外只有第一位为1的情况,也能将所有的位全部变成1,不过由于最后计算出来为int类型的最大值,此时返回n+1会导致溢出,不能返回期望的结果,这也是为什么在方法开始是要执行int n = c - 1;的原因。

三、tableSizeFor()的参数

那么为什么tableSizeFor()的参数为initialCapacity + (initialCapacity >>> 1) + 1而不是直接传入initialCapacity呢?

在ConcurrentHashMap有一个参数LOAD_FACTOR,默认值为0.75f。假设当前map容量为16,当其中的元素个数达到16*0.75f,也就是12个的时候,map为了最大化利用hash的作用,会进行扩容,也就是map中的元素个数一般不会达到容量的大小。

使用参数initialCapacity + (initialCapacity >>> 1) + 1来设置容量,不至于在初始化时就超过上诉"12"这个元素,并且能提供一些多余的空间,不至于在插入元素后马上就进行比较耗时的扩容操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值