Java·Hashtable、HashMap、ConcurrentHashMap的区别

关于HashMap详请见Java·hashmap
本文主要讲讲三者的区别

对比项 HashMap ConcurrentHashMap Hashtable 说明
基类 AbstractMap AbstractMap Dictionary 都实现了Map接口
数据结构 数组+链表 数组+链表 数组+链表
存储字段 Node[] table (volatile)Node[] table Entry[] table 都实现了Map.Entry接口
初始大小 16 16 11 尽量使哈希表的大小为奇数、素数
扩容策略 newsize = oldsize*2 newCap = oldCap << 1 参考 newCapacity = (oldCapacity << 1) + 1 当哈希表的大小为素数时,简单的取模哈希的结果会更加均匀
null键null值 允许,键为null的放在table[0]的哈希桶中 不允许 不允许 并发的都不允许参考
迭代器 Iterator(是 fail-fast 迭代器) enumerator(不是 fail-fast 迭代器) enumerator迭代key或value,Iterator迭代Entry(有 fail-fast 机制)参考
CAS自旋赋值+synchronized同步+LockSupport阻塞等手段,效率高 synchronized同步关键字,锁住整张表,效率低

ConcurrentHashMap锁

JDK7里面采用分段锁,最大并发个数就是Segment的个数,默认值是16,这个值就是并发的粒度;
JDK8里面,去掉了分段锁,而采用更细粒度的table元素级别,也就是说只需要锁住这个链表的head节点,并不会影响其他的table元素的读写,好处在于并发的粒度更细,影响更小,从而并发效率更好

ConcurrentHashMap扩容时的读写操作

  • (1)对于get读操作,如果当前节点有数据,还没迁移完成,此时不影响读,能够正常进行。 如果当前链表已经迁移完成,那么头节点会被设置成fwd节点(ForwardNode),此时get线程会帮助扩容。
  • (2)对于put/remove写操作,如果当前链表已经迁移完成,那么头节点会被设置成fwd节点,此时写线程会帮助扩容,如果扩容没有完成,当前链表的头节点会被锁住,所以写线程会被阻塞,直到扩容完成。

参考链接:
深入理解HashMap+ConcurrentHashMap的扩容策略
Hashtable 的实现原理
HashMap和Hashtable的区别
面试必备:HashMap、Hashtable、ConcurrentHashMap的原理与区别

你可能感兴趣的:(Java·Hashtable、HashMap、ConcurrentHashMap的区别)