HashMap

基于jdk1.7

类图

map类图

Map

Map内部子接口Entry (条目)

AbstractMap

对Map接口的方法进行实现,不对Entry接口进行实现,SimpleEntry(可变的) 和 SimpleImmutableEntry(不可变的),都是只有key value 两个属性

HashMap

HashMap 数据结构为数组(table[Entry])+ 链表(Entry.next),其Entry四个域,key,value,next,hash

HashMap几个比较重要的域

HashMap九个内部类

HashMap X问

1.为什么并发下会死循环

hash死循环发生在两个或多个线程同时对hashMap resize过程中 transfer会造成entry和它的next反转.entry的next又指向了next,造成死循环,照着耗子叔叔的走一遍就清楚了.

void transfer(Entry[] newTable)
{
    Entry[] src = table;
    int newCapacity = newTable.length;
    //  从OldTable里摘一个元素出来,然后放到NewTable中
    for (int j = 0; j < src.length; j++) {
        Entry<K,V> e = src[j];
        if (e != null) {
            src[j] = null;
            do {
                Entry<K,V> next = e.next;
                int i = indexFor(e.hash, newCapacity);
                e.next = newTable[i];
                newTable[i] = e;
                e = next;
            } while (e != null);
        }
    }
}

2.为什么其内部table的length都是2的幂

什么,不一定是2的幂?

一定的. 详情见HashMap#inflateTable -> HashMap#roundUpToPowerOf2 -> Integer.highestOneBit

扩容也是乘以2. 那么为什么要这么做呢?

可以保证entry分配均匀,在这里有讨论详见这里

3.hashCode如何提高HashMap的性能

具体在在equals hashcode中有讨论详见这里

4.EntrySet为何能遍历所有键值对

当初这么想的,EntrySet最多也只是能遍历所有Entry,在冲突的情况下,每个Entry上可能挂多个键值对,怎么能遍历所有的键值对呢.它重写了iterator()方法啊,不是AbstractSet的iterator()啊。妈的,源码中没带@Override标签,这也告诉我们重写的方法时最好是带上@Override,这对于读代码的人,有好处没坏处。

简直二逼啊!还是mark下吧。

5.ConcurrentHashMap为什么线程安全且高性能

分段锁,减少锁粒度,避免对整张表加锁

ConcurrentHashMap

参考

[1]http://mailinator.blogspot.com/2009/06/beautiful-race-condition.html

[2]http://coolshell.cn/articles/9606.html

[3]http://nanguocoffee.iteye.com/blog/907824

[4]http://blog.csdn.net/ns_code/article/details/36034955

[5]http://www.importnew.com/18633.html

[keySet 与entrySet 遍历HashMap性能差别]http://kim-miao.iteye.com/blog/736143

[Java 8系列之重新认识HashMap]http://tech.meituan.com/java-hashmap.html

[高性能场景下,HashMap的优化使用建议]http://calvin1978.blogcn.com/articles/hashmap.html