java.util.HashMap

来源:互联网 发布:淘宝宝贝图尺寸 编辑:程序博客网 时间:2024/06/13 05:54

      HashMap实现了Map接口,该接口的作用主要是为客户提供三种方式的数据显示:只查看keys列表;只查看values列表,或以key-value形式成对查看。Map接口并没有定义数据要如何存储,也没有指定如何判定key是一样,因此并不是所有的Map实现都会与hashCode方法扯上关系,如TreeMap便是要求对象实现Comparator接口,通过其compare方法来比对两者是否一致,而非hashCode及equals。同理,如果我们自己实现Map接口,我们也可以直接使用数组进行数据存储使用==判定key值是否一致,依然可以完全满足Map接口的定义。

      我们平常使用最多的莫过于HashMap,为何要使用它呢?它是一个Map接口的实现,内部使用的是数组及链表模式,它的过人之处在于它使用了hash算法,而使得查找某一key对应的Map.Entry对象比使用普通的数组更快,至于为何呢,可以查看这篇博文:深入Java集合学习系列:HashMap的实现原理(非本人的).

      尽管HashMap特别好用,但在某些特定情况下却会出现问题,最典型的一种情况便是多线程,HashMap原生是not thread-safe的,即是说多个线程可以同时调用其上的方法,没有任何的锁定,这样很容易产生脏数据等多线程问题,不仅如此,HashMap每次添加对象时都会检查是否达到数据阀值,如果是的话还会对内部存储数据的数据进行扩容,具体是将原数据内的数据迁移到容量为原来2倍的新数组上,不仅数组长度变化,连内部链表顺序也会颠倒,因此可以说是内部数据结构的大改变,而正是因为这种数据结构的变化造成了多线程下使用HashMap的隐患,现已知的一个重要的问题即是产生死循环,可通过此博文了解:HashMap 死循环的探究(亦非本人的 :)

      对此,JDK特别提供了Hashtable类,该类与HashMap类近乎相同,不同之处则在于其在各个方法上添加了synchronized关键字,这样便形成了一个线程安全的HashMap,这种方法可以说完全解决了HashMap多线程使用上的问题,但却同时增加了方法调用的资源消耗,相比于HashMap来说性能上有所下降。Hashtable的问题在于它使用的是整个对象的锁,每一次操作,它都会将整个对象锁定,则其它操作均无法进行,假设只是在原有key更换对象,同时对两个key操作,则其中一个必须等待,即使两个操作不是对同一个链表,显示这种做法有不合理之处。

       对于以上问题,JDK1.5后便引入到ConcurrentHashMap类,该类实现上亦类似于HashMap,但却有很大的不同,同样使用数组,但不再是一个数组,而是多个数组,每个数组中的对象又是一个链表,在方法调用过程中,不再对整个对象进行锁定,而是对其中的某一个数组进行锁定,此时对于其它数组的数据改动依然可以进行,可以说ConcurrentHashMap是介于Hashtable与HashMap之间的一个实现,SUN的工程师也为该类付出了很多的心血,可以说该类是多线程下HashMap的最好的代替,关于该类的详细信息可以看看下面两篇文章:Java 理论与实践: 并发集合类 及 ConcurrentHashMap之实现细节;

 

结论:单线程下使用HashMap,多线程下使用ConcurrentHashMap

 

相应参考资料有:

1.深入Java集合学习系列:HashMap的实现原理

2.HashMap 死循环的探究

3.Java 理论与实践: 并发集合类

4.ConcurrentHashMap之实现细节

5.轻松使用线程: 减少争用

6.Java 理论与实践: 构建一个更好的 HashMap

 

原创粉丝点击