Morse Code

也来谈谈java-HashMap

从源码中得到的信息:

1 HashMap没最大容量限制,超出Integer.MAX_VALUE后,size不准确。

void resize(int newCapacity) {
    Entry[] oldTable = table;
    int oldCapacity = oldTable.length;
    if (oldCapacity == MAXIMUM_CAPACITY) {
        threshold = Integer.MAX_VALUE;
        return;
    }
    Entry[] newTable = new Entry[newCapacity];
    transfer(newTable);
    table = newTable;
    threshold = (int)(newCapacity * loadFactor);
}

2 HashMap的hash,hash的目的是使其均匀,当然,没有重复是做好状态,相信很多人看过这段代码:

static int hash(int h) {
    // This function ensures that hashCodes that differ only by
    // constant multiples at each bit position have a bounded
    // number of collisions (approximately 8 at default load factor).
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}

猛一看,瞬间吓尿了。。我们来分析一下: 也可以看这里

public static void main ( String[] args ) {
    int h = 0xffffffff;
    int h1 = h >>> 20;
    int h2 = h >>> 12;
    int h3 = h1 ^ h2;
    int h4 = h ^ h3;
    int h5 = h4 >>> 7;
    int h6 = h4 >>> 4;
    int h7 = h5 ^ h6;
    int h8 = h4 ^ h7;

    printBin ( h );
    printBin ( h1 );
    printBin ( h2 );
    printBin ( h3 );
    printBin ( h4 );
    printBin ( h5 );
    printBin ( h6 );
    printBin ( h7 );
    printBin ( h8 );

}

static void printBin ( int h ) {
    System.out.println ( String.format ( "%32s",
                Integer.toBinaryString ( h ) ).replace ( ' ', '0' ) );
}

prints:

11111111111111111111111111111111
00000000000000000000111111111111
00000000000011111111111111111111
00000000000011111111000000000000
11111111111100000000111111111111
00000001111111111110000000011111
00001111111111110000000011111111
00001110000000001110000011100000
11110001111100001110111100011111

3 存储结构:

table&entry满足下面等式:

// 如果, 其中length是hashmap的长度,默认是1<<30
hash(entryA.key) = hash(entryB.key)
i = hash(entryA.key) & (length)
// 那么, 其中->表示指向,A.B的谁后添加,谁在前面
table[i] -> enrtyA & entryA.next -> entryB

4 cpu百分百问题:

真是挺纳闷为什么有那么多蛋疼的人包括自己在研究hashMap的这个问题,在不正当的使用情况下,如多个线程有些插入,有些读取,会出现cpu 100%的情况,有可能是get,有可能是put。

其中淘宝大牛应该分析出了一些情况,但是感觉有些片面。因为扩容之后,以前同一个table[i]下的节点,不一定映射到新table的同一个i上,加之java内存屏障的存在,非线程安全的方法,线程间同步共享变量的时机模糊不定。

在自己做的试验里面:

所以大家知道会出问题就好,不要乱折腾这个了,说不定不同版本的jdk的源码都不一样呢。

絮絮叨叨一大堆。说给自己吧。看《蛇蝎美人》去了。