【JDK1.8-ConcurrentHashMap】tableSizeFor(int c)方法理解

       JDK1.8对ConcurrentHashMap进行了一些改动,因此照着源码和网上博客看看究竟有哪些改动?还没看一小会儿,就发现了一个方法比较硬咬不动,因此研究了一下,并记录下对该方法的理解。
       ConcurrentHashMap有一个构造函数,请看下面!

public ConcurrentHashMap(int initialCapacity) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException();
        int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
                   MAXIMUM_CAPACITY :
                   tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
        this.sizeCtl = cap;
    }

它是一个带有参数的构造函数,可以指定ConcurrentHashMap初始化的大小,但是由于“神秘的里力量”,ConcurrentHashMap初始化大小始终为2幂次(为什么需要初始化成2的幂次呢?),例如:

 1. Map map = new ConcurrentHashMap(2)    其实初始化的大小为4
 2. Map map = new ConcurrentHashMap(14)   其实初始化的大小为32
 3. Map map = new ConcurrentHashMap(16)   其实初始化的大小为32
 4. Map map = new ConcurrentHashMap(128)  其实初始化的大小为256

是谁,将初始化的大小变为2的幂次,是“他”,本篇主角 tableSizeFor(int c),“他”到底做了什么,先来看看方法的全貌:

    /**
     * Returns a power of two table size for the given desired capacity.
     */
    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;
    }

注释讲得不是很中国化,可能需要百度翻译一下:

Returns a power of two table size for the given desired capacity.
中译
给定一个期望的初始化大小值,返回一个2次幂大小值

咋一看这个方法不是很懂,很(感)(觉)(很)(高)(大)(上)(的)(样)(子),看的一脸懵逼!
于是仔细研究了一下,下面发现很巧妙!下面解析一下,“他”是如何做到的。我们知道JAVA当中的int基本数据类型所占的字节数是4Bytes,也就是32bits;>>> or <<<在JAVA中表示无符号移位。好的知道这些就可以开工啦!!!
1.试想一下如果c = 0也就是下面这个样子

c:0000 0000 0000 0000 0000 0000 0000 0000  32bits

给方法里面的代码做上标记:
(1)int n = c - 1;
(2)n |= n >>> 1;
(3)n |= n >>> 2;
(4)n |= n >>> 4;
(5)n |= n >>> 8;
(6)n |= n >>> 16;
(7)return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
执行(1)之后c < 0很显然最后返回的结果为1
2.如果c > 0也就是下面这样

c:0000 0000 0000 0000 0010 0000 0000 0010  32bits
or
c:1000 0000 0000 0000 0010 0000 0000 0010  32bits
or
c:0000 0000 0000 0100 0010 0000 1000 1010  32bits
...

可以发现如果c > 0话,就一定会出现一个分割点1在它的左边全是0或者没有数据了。如果我们将这个1往右移一位也就是代码(2),再与n本身|一下,那么n中至少有21,也就是下面c3标红的两个1
举例:
c1:0000 0000 0000 0100 0010 0000 1000 1010   32bits
c2:  000 0000 0000 0010 0001 0000 0100 01010 32bits c1移一位
c3:0000 0000 0000 0110 0011 0000 1100 1111     32bits c1与c2或
接上c3执行代码(3)也就是c3两个红11右移两位(也就是c4
c3:0000 0000 0000 0110 0011 0000 1100 1111          32bits
c4:    00 0000 0000 0001 1000 1100 0011 0011 11     32bits
c5:0000 0000 0000 0111 1011 1100 1111 1111            32bits c3与c4或

如果n是够大的话,那么n是不是最少有四个1,然后执行(4)就是8个1,(5)就是16个1,(6)就是32个1,最终执行完(2)(3)(4)(5)(6),n如果够大是不是32位都是1。因此,如果n > 0,经过(2)(3)(4)(5)(6)这五步,n所有有效位都能置为1,最后执行(7)就是2次幂的数了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章