目录
引言
面试题:hashmap原理
原理
JDK7时HashMap的数据结构
jdk8中hashMap数据结构
hashMap怎么设置初始值的大小
jdk7和jdk8中HashMap的区别
为什么放在hashMap集合key部分的元素需要重写equals方法?
concurrenthashmap为什么线程安全
高频面试题
参考
引言
目前各大互联网大小厂往往喜欢考察原理性的东西。 这里总结高频出现的问题,供大家参考。
面试题:hashmap原理
HashMap基于Map接口实现,元素以键值对的方式存储,并且允许使用null建和null值,因为key不允许重复,因此只能有一个键为null,另外HashMap不能保证放入元素的顺序,它是无序的,和放入的顺序并不能相同
原理
其底层数据结构是数组称之为哈希桶,每个桶(bucket)里面放的是链表,链表中的每个节点,就是哈希表中的每个元素。
通过hash的方法,通过put和get存储和获取对象。
- 存储对象时,我们将K / V传给put方法时,它调用hashCode计算hash从而得到bucket位置,进一步存储,HashMap会根据当前bucket的占用情况自动调整容量 (超过 Load Facotr则resize为原来的2倍)。
- 获取对象时,我们 K传给get,它调用hashCode()计算hash从而得到bucket位置,并进一步调用equals()方法确定键值对。如果发生碰撞的时候,Hashmap通过链表将产生碰撞冲突的元素组织起来,在JDK8中,如果一个bucket中碰撞冲突的元素超过8个,则使用红黑树来替换链表,从而提高速度。
因其底层哈希桶的数据结构是数组,所以也会涉及到扩容的问题
当HashMap的容量达到threshold域值时,就会触发扩容。扩容前后,哈希桶的长度一定会是2的次方。这样在根据key的hash值寻找对应的哈希桶时,可以用位运算替代取余操作,更加高效。
而key的hash值,并不仅仅只是key对象的hashCode()方法的返回值,还会经过扰动函数的扰动,以使hash值更加均衡。
JDK7时HashMap的数据结构
1、在JDK7之前,hashmap底层采用数组+链表的数据结构来存储数据
2、插入数据采用头插法,头插法效率更高,不需要去遍历链表。插入结点后将头结点移到数组下标的位置
HashMap主要是用数组来存储数据的,我们都知道它会对key进行哈希运算,哈希运算会有重复的哈希值,对于哈希值的冲突,HashMap采用链表来解决的。
jdk8中hashMap数据结构
1、JDK8以后hashmap的底层数据结构由数据+链表+红黑树实现
2、jdk8以后插入数据采用尾插法。因为引入了树形结构,总是要遍历的
JDK8之后,如果哈希表单向链表中元素超过8个,那么单向链表这种数据结构会变成红黑树数据结构。当红黑树上的节点数量小于6个,会重新把红黑树变成单向链表数据结构:
hashMap怎么设置初始值的大小
如果你在创建的时候没有设置初始值大小,那么它的默认容量是16。
如果你设置了一个初始容量,它会先进行一个判断,判断这个值是不是2的次幂,如果不是将会把容量转化成为2的次幂大小。比如说你设置的容量是27,那么创建的HashMap实际容量是32。
jdk7和jdk8中HashMap的区别
1、jdk8中当链表长度大于8时会将链表转化成为红黑树
2、节点插入顺序不同,jdk7采用头插法,而jdk8采用尾插法
3、hash算法的简化
为什么放在hashMap集合key部分的元素需要重写equals方法?
因为equals默认比较是两个对象内存地址
concurrenthashmap为什么线程安全
- ConcurrentHashMap 在 JDK 1.7 时使用的是数据加链表的形式实现的,其中数组分为两类:大数组 Segment 和小数组 HashEntry,而加锁是通过给 Segment 添加 ReentrantLock 锁来实现线程安全的。
- 而 JDK 1.8 中 ConcurrentHashMap 使用的是数组+链表/红黑树的方式实现的,它是通过 CAS 或 synchronized 来实现线程安全的,并且它的锁粒度更小,查询性能也更高。
在JDK 1.7中,ConcurrentHashMap采用了分段锁技术来保证线程安全。具体地,ConcurrentHashMap将整个Map分为若干个Segment,每个Segment拥有自己的锁。不同的线程可以同时访问不同的Segment,从而实现了并发访问。当对某个Segment进行修改时,只需要锁住该Segment的锁,而不用锁住整个Map,从而减少了锁竞争和锁持有时间,提高了并发性能。
在JDK 1.8中,ConcurrentHashMap对内部数据结构进行了优化,采用了基于CAS操作的无锁算法来实现线程安全。具体地,ConcurrentHashMap将整个Map分为若干个Node数组,每个Node包含一个key-value对和一个指向下一个Node的引用。当多个线程并发地访问和修改Map时,采用CAS操作来保证原子性和可见性。当需要对某个Node进行修改时,首先需要通过CAS操作将该Node的状态从“未修改”改为“修改中”,然后进行修改操作,最后通过CAS操作将该Node的状态从“修改中”改为“修改完成”。这样可以避免锁竞争和死锁等问题,同时也提高了并发性能。
参考链接:https://juejin.cn/post/7205582597392252989
为什么ConcurrentHashMap是线程安全的?_concurrentmap为什么线程安全_柒柒Java的博客-CSDN博客
高频面试题
HashMap的工作原理是什么?
HashMap中的“死锁”是怎么回事?
解决:使用ConcurrentHashMap
HashMap中能put两个相同key吗?为什么?
HashMap中的键值可以为null吗?原理? 当key==null的时候,key的hashcode = 0;不会抛出空指针异常
HashMap扩容机制?
参考
JDK8中HashMap的工作原理剖析-腾讯云开发者社区-腾讯云