1.前言
对于HashMap,大家知道存的是键值对,对于ConcertHashMap 大家了解的是用于并发编程中。除了这些初步的印象,对他们之间的区别还需要知道些什么呢,数据结构是不是越复杂越好?在开发过程当中轻量级的容器更好,还是多功能的容器结构更好呢,这些都要开发者去评估。
2.HashMap
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
}
对于hashMap,实现了Cloneable的接口,而这是需要注意的
3.ConcurrentHashMap
public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable {
}
对于ConcurrentHashMap 并没有实现Cloneable接口,但是实现了ConcurrentMap接口。这是为什么呢,原因就在于你要实现复制容器的接口,就必须要去读和写容器,而这在并发编程当中是存在问题的,即如何保证并发编程三要素,原子性,可见性,有序性。这里主要考虑的是违反了并发编程的可见性,多个线程操作一个容器的时候,哪个线程先读取,哪个线程可以先修改,这些都是HashMap不支持的。
3.其他简单区别
HashMap实现的方法和ConurrentHashMap实现的方法
在ConcurrentHashMap中变量用volatile修饰。
/**
* The array of bins. Lazily initialized upon first insertion.
* Size is always a power of two. Accessed directly by iterators.
*/
transient volatile Node<K,V>[] table;
ConcurrentHashMap最重要的是segment类,继承了ReentrantLock锁
ConcurrentHashMap 采用了分段锁技术,不会像 HashTable 那样不管是 put 还是 get 操作都需要做同步处理,理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数量)的线程并发。每当一个线程占用锁访问一个 Segment 时,不会影响到其他的 Segment。
static class Segment<K,V> extends ReentrantLock implements Serializable {
private static final long serialVersionUID = 2249069246763182397L;
final float loadFactor;
Segment(float lf) { this.loadFactor = lf; }
}
有兴趣的可以阅读其他文档,对于HashMap的容器扩容,hash函数,hash冲突,ConcurrentHashMap的reentrantLock锁讲的更加详细,本篇作为记录其他开发者codeReview,质疑你使用concurrentHashMap,为什么不用更轻的hashMap,接口之后是否会有性能问题,需要引入并发,这值得每个人思考。