关于HashMap的一些总结

63 阅读3分钟

HashMap 的底层数据结构和解决冲突方式:

底层数据结构:

HashMap 的底层数据结构是数组和链表(或红黑树)。数组的每个元素称为桶(bucket),每个桶存放一个链表(或红黑树)。

Hash 冲突解决:

当两个不同的键通过哈希函数映射到同一个桶时发生冲突。HashMap 使用链表(或红黑树)来解决冲突:

  1. 链表法: 将相同哈希值的键值对放到同一个桶中,通过链表进行连接。
  2. JDK8+红黑树: 当链表长度超过一定阈值(默认为8),将链表转化为红黑树,提高查找效率。

JDK8 中的优化:

JDK8 对 HashMap 进行了很多优化,其中一个主要的优化是引入了红黑树来代替链表,提高了在发生哈希冲突时的查询效率。具体改进包括:

  1. 红黑树替代链表: 当链表长度超过一定阈值时,将链表转换为红黑树。
  2. 树化和退树化: 在红黑树和链表之间进行树化和退树化的操作,以适应不同的场景。
  3. 更好的哈希算法: 采用了新的哈希算法,增强了分布均匀性。

红黑树的实现原理和优劣势:

实现原理:

红黑树是一种自平衡的二叉查找树,它在每个节点上都维护了额外的信息表示节点的颜色,可以是红色或黑色。通过在插入和删除等操作后进行旋转和变色操作,确保树的高度平衡,从而保证了查找、插入、删除等操作的时间复杂度为 O(log n)。

优势:

  1. 平衡性: 红黑树是自平衡的,能够保持较低的高度,因此查找、插入、删除等操作效率较高。
  2. 支持范围查询: 由于树是有序的,红黑树支持范围查询。

劣势:

  1. 复杂性: 相较于简单的链表,红黑树的实现和维护更为复杂。
  2. 空间开销: 红黑树需要额外的空间存储颜色信息,相对于链表会占用更多的内存。

HashMap 的线程安全性和 ConcurrentHashMap:

HashMap 线程安全性:

HashMap 不是线程安全的。在多线程环境下,如果有一个线程在修改 HashMap 结构,而另一个线程在遍历该 HashMap,可能会导致 ConcurrentModificationException 异常。因此,在多线程环境下,需要进行外部同步。

ConcurrentHashMap 的线程安全性:

ConcurrentHashMap 是 Java 中专门为多线程设计的哈希表实现,它通过将数据分段(Segment)来降低锁的粒度,提高并发度,从而实现更好的性能。

  1. 分段锁: ConcurrentHashMap 使用了分段锁,将整个数据集分成多个段(Segment),每个段独立加锁,不同的线程可以同时访问不同的段,提高并发性能。
  2. 读写分离: 读操作不需要加锁,多个线程可以同时执行读操作,写操作只需要锁定对应的段,而不是整个表。

ConcurrentHashMap 在高并发环境下提供了较好的性能,但在一些特殊场景下,仍需注意可能产生的一些问题,如迭代时的弱一致性。