JDK8和JDK7 HashMap的区别
什么是HashMap
Hashmap是一种快速的查找并且插入、删除性能都良好的一种 K/V键值对的数据结构,它基于哈希表的 Map 接口实现,是常用的 Java 集合之一,是非线程安全的。
区别
JDK7 | JDK8 | |
---|---|---|
底层结构 | 数组+链表(hash冲突元素使用链表存储,使用头插法) | 数组+链表(使用尾插法)+红黑树(当链表长度超过8时,采用红黑树存储) |
存储结构 | 使用Entry数组存储数据 | 使用Node数组存储数据 |
扩容机制 | 执行transfer()方法扩容,先扩容再插入新值。扩容后新的hash值,通过重新hash确定 | 执行reSize()方法扩容,先插入新值在扩容 。扩容后新的hash值,通过更加简单的方式处理,提升效率(通过原hash值 & 原容量 - 1) |
线程安全 | 线程不安全(多线程存储数据存在环状问题) | 线程不安全(多线程存储数据出现数据覆盖问题) |
hash算法 | 为了提高遍历效率,所以需要提高hash散列值,所以对hash算法进行复杂化 | 优化哈希算法,因为采用红黑树,大幅度提升了遍历速度,所以为了更好的效率,相对简化hash算法 |
重点疑问点
-
为什么在链表长度达到阈值(默认为8)之后,需要转变成红黑树。都是平衡二叉树,为什么使用红黑树,而不是用AVL(平衡二叉树)?
- 我们都知道,链表在插入的时候速度是最快的,时间复杂度为O(1),但是在读取的时候是O(n),因为需要通过头节点一个个往后遍历,所以当我们的链表长度越来越大的时候,hashMap读取的时间也会越来越大,导致查找的效率变低。而红黑树是一种平衡二叉树,可以自适应的进行长度平衡,使其时间复杂度降低为O(lg n),很大程度上提升了查找效率
- 至于为什么不使用AVL呢,因为AVL和红黑树虽然都是一种平衡二叉树,他们的时间复杂度都可以达到O(lg n),但是AVL是一种比红黑树更加严格的平衡,所以这也导致了AVL在进行数据插入之后需要进行更多次数的反转之后才能维持AVL的平衡,所以AVL更适合读取查找密集型任务,而红黑树更加适合hashMap这种插入修改密集型任务。
-
为什么在JDK7链表插入是使用头插法,而到JDK8使用尾插法呢?头插法不是比尾插法效率更高吗?
- 主要是为了修复并发状态下JDK7扩容时使用头插法产生的环状问题,环状问题产生会导致CPU飙升。
- 以下为JDK7使用头插法,导致环状问题产生的代码:
void resize(int newCapacity) {
Entry[] oldTable <