HashTable、HashMap、LinkedHashMap、TreeMap、ConcurrentHashMap之间的区别

 

HashTable、HashMap、LinkedHashMap、TreeMap、ConcurrentHashMap之间的区别_第1张图片 MapMap接口

 

一:HashTable与HashMap之间的区别

 

  HashTable HashMap
内部存储元素   无序
底层实现 数组+链表 数组+链表
实现原理    
效率
null 不接受null key、null value 可接受null key、null value
线程同步 同步[synchronized实现] 不同步
线程安全 synchronized[线程安全] 非synchronized[线程不安全]
扩容方式 old * 2 + 1 old * 2
默认容量 11 16
父类 Dictionary AbstractMap
方法 contains() containsKey()、contaionsValue()

延伸:

HashMap的底层实现:

有文章提到:HashMap的实现原理为:基于拉链法的散列表,也有文章说是:散列表。到底是什么呢?

哈希表[hash table]也叫散列表,哈希表的主干就是数组。

 

数据结构的物理存储结构只有两种:顺序存储结构链式存储结构(像栈,队列,树,图等是从逻辑结构去抽象的,映射到内存中,也这两种物理组织形式)。

 

HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对。

 

 

 

相同点:

同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口

 

HashMap同步的方式

Map m = Collections.synchronizeMap(hashMap);

HashTable已经被淘汰了,不要在代码中再使用它。

以下描述来自于HashTable的类注释:

If a thread-safe implementation is not needed, it is recommended to use HashMap in place of Hashtable. If a thread-safe highly-concurrent implementation is desired, then it is recommended to use java.util.concurrent.ConcurrentHashMap in place of Hashtable.

简单来说就是,如果你不需要线程安全,那么使用HashMap,如果需要线程安全,那么使用ConcurrentHashMap。HashTable已经被淘汰了,不要在新的代码中再使用它。

ConcurrentHashMap实现原理:支持并发读写的HashMap,特点:读取数据时无需加锁,写数据时可以保证加锁粒度尽可能的小。内部采用“分段存储”。

 

二:HashMap、LinkedHashMap、TreeMap之间的区别

 

  HashMap LinkedHashMap TreeMap
       
迭代顺序 随着时间的推移,不保证顺序将维持不变 插入顺序 根据自然顺序排序

Get/put

remove

containsKey

时间复杂度

O(1) O(1) O(log(n))
接口类 Map Map

NavigableMap

Map

SortedMap

Null

Values/Key

允许 允许 仅values
底层实现 buckets 双向链表+buckets 红黑树
线程安全 不安全
       
    能够记住元素插入的顺序  

HashMap 是基于散列表,并且用拉链法来解决哈希冲突的。所以 HashMap 的底层数据结构是 “数组 + 链表”,即元素是链表的数组。不过当链表的元素个数超过一个阀值( static final int TREEIFY_THRESHOLD = 8; )的时候,会将链表转换为红黑树,所以如果哈希冲突多的话,数组的元素将会是红黑树。

 concurrentMap 和 HashMap 区别

  1. hashMap可以有null的键,concurrentMap不可以有

  2. hashMap是线程不安全的,在多线程的时候需要Collections.synchronizedMap(hashMap),ConcurrentMap使用了重入锁保证线程安全。

  3. 在删除元素时候,两者的算法不一样。

  4. ConcurrentHashMap和Hashtable主要区别就是围绕着锁的粒度以及如何锁,可以简单理解成把一个大的HashTable分解成多个,形成了锁分离。

 ConcurrentHashMap中的扩容是否需要对整个表上锁?

  • 通过给每个线程分配桶区间(默认一个线程分配的桶是16个),避免线程间的争用。

  • 通过为每个桶节点加锁,避免 putVal 方法导致数据不一致。

  • 同时,在扩容的时候,也会将链表拆成两份,这点和 HashMap 的 resize 方法类似。

引用:

https://blog.csdn.net/haihui_yang/article/details/80642520

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Java基础)