面试官:HashMap实现原理是什么?HashMap是线程安全的吗?

本文详细介绍了HashMap的实现原理,包括其数据结构、扩容机制、JDK1.8的优化以及从链表到红黑树的转换。同时,文章讨论了HashMap的线程不安全问题,解析了ConcurrentHashMap如何通过分段锁和CAS实现并发安全,并对比了JDK1.7与JDK1.8中ConcurrentHashMap的优化策略。
摘要由CSDN通过智能技术生成

面试题1:说一下 HashMap 的实现原理?

  • 追问1:如何实现HashMap的有序?
  • 追问2:那TreeMap怎么实现有序的?
  • 追问3:put方法原理是怎么实现的?
  • 追问4:HashMap扩容机制原理
  • 追问5:HashMap在JDK1.8都做了哪些优化?
  • 追问6:链表红黑树如何互相转换?阈值多少?

面试题2:HashMap是线程安全的吗?

  • 追问1:你是如何解决这个线程不安全问题的?
  • 追问2:说一下大家为什么要选择ConcurrentHashMap?
  • 追问3:ConcurrentHashMap在JDK1.7、1.8中都有哪些优化?

面试题1:说一下 HashMap 的实现原理?

正经回答:

众所周知,HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry(包括Key-Value),其中Key 和 Value 允许为null。这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干。另外,HashMap数组每一个元素的初始值都是Null。

面试官爆锤HashMap:HashMap实现原理?HashMap是线程安全的吗?

值得注意的是:HashMap不能保证映射的顺序,插入后的数据顺序也不能保证一直不变(如扩容后rehash)。

要说HashMap的原理,首先要先了解它的数据结构

面试官爆锤HashMap:HashMap实现原理?HashMap是线程安全的吗?

如上图为JDK1.8版本的数据结构,其实HashMap在JDK1.7及以前是一个“链表散列”的数据结构,即数组 + 链表的结合体。JDK8优化为:数组+链表+红黑树。

我们常把数组中的每一个节点称为一个桶。当向桶中添加一个键值对时,首先计算键值对中key的hash值(hash(key)),以此确定插入数组中的位置(即哪个桶),但是可能存在同一hash值的元素已经被放在数组同一位置了,这种现象称为碰撞,这时按照尾插法(jdk1.7及以前为头插法)的方式添加key-value到同一hash值的元素的最后面,链表就这样形成了。

当链表长度超过8(TREEIFY_THRESHOLD - 阈值)时,链表就自行转为红黑树。

注意:同一hash值的元素指的是key内容一样么?不是。根据hash算法的计算方式,是将key值转为一个32位的int值(近似取值),key值不同但key值相近的很可能hash值相同,如key=“a”和key=“aa”等

通过上述回答的内容,我们明显给了面试官往深入问的多个诱饵,根据我们的回答,下一步他多可能会追问这些问题:

1、如何实现HashMap的有序?

4、put方法原理是怎么实现的?

6、扩容机制原理 → 初始容量、加载因子 → 扩容后的rehash(元素迁移)

2、插入后的数据顺序会变的原因是什么?

3、HashMap在JDK1.7-JDK1.8都做了哪些优化?

5、链表红黑树如何互相转换?阈值多少?

7、头插法改成尾插法为了解决什么问题?

而我们,当然是提前准备好如何回答好这些问题!当你的回答超过面试同学的认知范围时,主动权就到我们手里了。

追问1:如何实现HashMap的有序?

使用LinkedHashMap 或 TreeMap。

LinkedHashMap内部维护了一个单链表,有头尾节点,同时LinkedHashMap节点Entry内部除了继承HashMap的Node属性,还有before 和 after用于标识前置节点和后置节点。可以实现按插入的顺序或访问顺序排序。

/**
 * The head (eldest) of the doubly linked list.
*/
transient LinkedHashMap.Entry<K,V> head;

/**
  * The tail (youngest) of the doubly linked list.
*/
transient LinkedHashMap.Entry<K,V> tail;
//将加入的p节点添加到链表末尾
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
  LinkedHashMap.Entry<K,V> last = tail;
  tail = p;
  if (last == null)
    head = p;
  else {
    p.before = last;
    last.after = p;
  }
}
//LinkedHashMap的节点类
static class Entry<K,V> extends HashMap.Node<K,V> {
  Entry<K,V> before, after;
  Entry(int hash, K key, V value, Node<K,V> next) {
    super(hash, key, value, next);
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值