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;
}

 

转载于:https://www.cnblogs.com/yang4869/p/11078816.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ConcurrentHashMapsize方法返回当前映射中键值对的数量。由于ConcurrentHashMap是线程安全的,因此在多个线程同时访问时,size方法可能会返回一个近似值,而不是精确的值。这是因为在多个线程同时进行插入、删除等操作时,size方法需要遍历整个映射,而这个过程中可能会有其他线程同时进行修改操作,导致size方法返回的值不是最新的。因此,ConcurrentHashMapsize方法适用于需要一个近似值的场景,如果需要精确的值,可以使用其他方法,如遍历整个映射并计数。 ### 回答2: ConcurrentHashMapsize方法是用来获取当前ConcurrentHashMap中键值对的数量的。ConcurrentHashMap是Java中的一个线程安全的哈希表,它通过细粒度的锁机制来实现多线程并发访问的效率。 在ConcurrentHashMap中,不同的线程可以同时进行读取操作,而且读取操作不需要加锁,这大大提高了读取操作的效率。但是如果有多个线程同时进行写入操作,那么这些写入操作就需要加锁来保证线程安全。 在ConcurrentHashMap的实现中,为了同时满足读取的高效率和写入的线程安全,ConcurrentHashMap使用了分段锁机制。它将整个哈希表分成了多个段(Segment),每个段都有自己的锁。这样不同的线程在写入操作时,只需要获取对应段的锁,而不会影响其他段的读取操作。这就保证了ConcurrentHashMap在并发场景下的高性能。 ConcurrentHashMapsize方法的原理是遍历整个哈希表,统计各个段中的键值对数量,并将其累加得到最终的结果。由于ConcurrentHashMap的读取操作不需要加锁,所以在统计的过程中,其他线程可以进行并发的读取操作。 需要注意的是,由于ConcurrentHashMapsize方法是通过遍历整个哈希表来统计数量的,所以在极端的高并发场景下,size方法的返回结果可能不是完全准确的。不过在大多数情况下,ConcurrentHashMapsize方法还是可以提供一个相对准确的结果的。 ### 回答3: ConcurrentHashMap是Java中的一个线程安全的哈希表实现,它继承自HashMap并通过使用锁分段技术来实现高并发性能。 ConcurrentHashMapsize()方法用于获取当前哈希表中键值对的数量。该方法通过遍历哈希表的所有段(每个段都是一个小的哈希表),获取每个段中的键值对数量,并将这些数量累加得到最终的结果。由于ConcurrentHashMap的并发性能较高,所以在计算size()的过程中,其他线程可以继续执行其他操作,不会被阻塞。 在计算size()的过程中,如果有其他线程对哈希表进行插入、删除或更新操作,那么在计算结果时可能会发生一些变化。为了保证计算结果的准确性,ConcurrentHashMap使用了一些特殊的技术来解决并发冲突,如使用volatile修饰符保证可见性、使用CAS(Compare and Swap)操作来保证原子性等。 需要注意的是,由于ConcurrentHashMapsize()方法是基于估计值计算得到的,所以在某些情况下,它可能无法返回准确的结果。比如,在计算size()的同时,有其他线程不断地进行插入或删除操作,那么返回的结果可能比实际的键值对数量要大或小一些。如果对结果的准确性有较高的要求,可以考虑使用其他方式来获取准确的数量,例如迭代哈希表并计算实际存在的键值对数量。 总之,ConcurrentHashMapsize()方法是用于获取线程安全哈希表中键值对数量的方法,它通过分段的方式来保证高并发性能,并通过一些特殊的技术来解决并发冲突。但是需要注意的是,由于size()方法是基于估计值计算得到的,所以结果可能不是完全准确的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值