HashMap、HashTable和ConcurrentHashMap的区别

HahMap、HashTable和ConcurrentHashMap的区别:

HashMap HashTable ConcurrentHashMap
null键 允许 不允许 不允许
null值 允许 不允许 不允许
效率 非常高
线程安全 不安全 安全 安全
数据结构 数组+链表+红黑树 数组+链表 数组+链表+红黑树
同步方式 synchronized同步方法 1.7版本:基于segment分段锁机制,基于ReentrantLock实现;1.8版本:基于CAS+synchronized实现,空节点插入使用CAS,有Node节点则使用synchronized加锁
迭代器类型 fail-fast迭代器:在遍历时不断更新元素,否则将抛出异常 fail-safe迭代器:基于容器的克隆,因此遍历操作时元素的更新不影响遍历 fail-safe迭代器:基于容器的克隆,因此遍历操作时元素的更新不影响遍历

各自实现的原理:

HashMap:

1.HashMap实现了Map接口, HashMap的默认初始容量是16,最大容量为2的30次方;

2.何时链表和红黑树相互转化:
若链表中节点个数超过8时,会将链表转化为红黑树;
若红黑树中节点小于6时,红黑树退还为链表;
如果哈希桶中某条链表的个数超过8,并且桶的个数超过64时才会将链表转换为红黑树,否则直接扩容。

3.HashMap桶中放置的节点—该节点是一个单链表的结构:Entry单向链表,当准备添加一个key-value对时,首先使用key借助hash函数计算key的哈希地址,再将key-value键值对,结合计算出的hash地址插入到哈希桶中。

4.HashMap是基于哈希表实现的,存储的数据是key-value键值对,实现了Serializable接口,Cloneable接口,所以它也支持序列化,能被克隆。

HashTable:

1.HashTable同样是基于哈希表实现,存储的数据同样为key-value键值对,其内部也是通过单链表解决哈希冲突的,容量不足时,同样会自动扩容;

2.线程安全,可以用于多线程场景。它的线程安全实现方式是:所有的方法都使用synchronized加锁,像一些读操作不存在线程不安全问题,所以全部方法加锁导致了效率低下。

3.现在已经被丢了不再使用了。不涉及线程安全问题时使用HashMap,要保证线程安全时,使用ConcurrentHashMap。

ConcurrentHashMap:

1.7版本:

1.底层数据结构还是数组+链表。HashEntry为链表的节点。

2.采用了segment分段锁技术,在多线程并发更新操作时,对同一个segment进行同步加锁,保证数据安全,这样就可以基于不同的segment进行并发写操作。

3.继承ReentrantLock实现同步锁机制。

4.和HashMap一样,都存在hash冲突,链表查询效率低的问题。
HashMap、HashTable和ConcurrentHashMap的区别_第1张图片

1.8版本:

1.底层数据结构和HashMap 1.8版本一样,都是数组+链表+红黑树;

2.支持多线程并发操作,实现原理:CAS+synchronized保证并发更新;

3.put方法放元素的时候:通过key对象的hashcode计算出数组的索引,如果没有Node,则使用CAS尝试插入元素,失败则无条件自旋,直到插入成功为止,如果存在Node,则使用synchronized锁住该Node元素(链表/红黑树的头节点),再执行插入操作。
HashMap、HashTable和ConcurrentHashMap的区别_第2张图片
1.7和1.8版本共同有的特征:

1.读操作没有加锁,value是volatile修饰的,保证了可见性,所以是安全的;
2.读写分离可以提高效率:多线程对不同的Node/Segment的插入/删除是可以并发、并行执行的,对同一个Node/Segment的写操作是互斥的。读操作是无锁状态,可以并发、并行执行。

你可能感兴趣的:(数据结构,数据结构,java)