ConcurrentHashMap之tableSizeFor()方法透析(位运算运用)

 
ConcurrentHashMap和HashMap有如下方法
inttableSizeFor(int c)
//功能:输入低于最大容量的数c,返回大于等于且最接近c的2的幂次数。
源码:
 
private static final int MAXIMUM_CAPACITY = 1 << 30;
 
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;
}

 

解释/总结1:符号>>:右移n位相当于除以2的n次方。符号<<:左移n位就相当于乘以2的n次方。 >>>无符号右移:"零扩展",无论正负,左边都补0。|符号,按位或,使用二进制计算:0|1=1,0|0=0,1|1=1
2:设c=010001101,即141.
执行:先减1,n=140--转为2进制---010001100  
    n |= n >>> 1------无符号右移一位,左边补0
    001000110 |       |操作
    010001100   
->n=011001110
    n |= n >>> 2------同上
    011001110 | 
    000110011     
->n=011111111=255
最高位1后面已经均为1,后面再执行|操作n不会发生变化了,
最后n=255,返回n+1即256。可以看出该算法通过几次无符号右移和|操作会让最高位的1后面的位全变为1。
3:在使用位运算之前减1是必要的,否则对于c=16,最后就会得到32.实际需求应当返回16.
4:为什么最后写到n|n >>> 16?我们知道int范围在-2^31~2^31-1,因此对于int最大的2次幂数为2^30,这也就是MAXIMUM_CAPACITY的值。c超过这个值就会返回MAXIMUM_CAPACITY。
而这边代码中一共右移了1+2+4+8+16=31位,因此可以保证高位1以下的低位都会变成1.
5:如果c是负数,那么结果如何
int c=-100;
c|= c >>> 1;
System.out.println( c );
c|= c >>> 2;
System.out.println( c );
c|= c >>> 4;
System.out.println( c );
c|= c >>> 8;
System.out.println( c );
结果:
-34
-1
-1
-1

 

运算过程中|操作后使用补码运算同样会不断的将0变成1;最后就会变成111111111111111111...=-1
 
实践发现如果传入负数最后n最大会变成-1,而上述算法中(n < 0) ? 1会返回1,不会有异常.

 
6:总结:这个算法主要是对位运算的运用.这里我总结一下位运算的运用
 |按位或运算:可以将指定的低位从0变成1,如a|0111 (2进制),这样就可以将低3位 置为1.
 ^异或运算:这个运算是相同的位得0,不同的得1. 它可以用来反转低位得值.如
1001^0111(2进制) =1110,后三位反转了.还有之前学过的可以用来交换a,b: a=a^b;b=b^a;a=a^b;
&按位与操作:可以用来保留后n位:如:010101&0111=000101这样保留后三位不变,其余为0.
<<左移:左移n等同于乘以2的n次方
>>右移:右移n等同于除以2的n次方,正数右移高位补0,负数右移高位补1
>>>无符号右移:无论是正数还是负数,高位都补0。
(左移右移时需要注意范围)
 
应用:
//判断两个int类型数是否同正负:
//只要看高位的数是不是不同即可
public static boolean SameSymbolInt(int a,int b){
    return ((a >> 31) ^ (b >> 31)) == 0;
}

 

posted @ 2019-06-24 18:55  杨守鹤  阅读(1064)  评论(0编辑  收藏  举报