每日面试题打卡(容器篇)——Day12

博主个人博客网站:文客
这个系列会长期更新!
如果你想每天和我打卡面试题、交流技术,可以关注一下我的个人博客网站:文客,我会每天在这里更新技术文章和面试题,也会及时收到大家的评论与留言,欢迎各位大佬来交流!

HashMap是怎么解决哈希冲突的

我们知道hashCode()返回的是整数,范围大概在-2^31 ~ 2^31-1 这个范围,而我们HashMap的容量只有16 ~ 2^30。如果直接用hashCode作为下标的话,会出现不匹配的情况。为了让每个对象都有对应的存储空间,就必须对hashCode进行压缩,压缩的算法就是哈希算法,也叫哈希函数/散列函数,由于散列值的空间远远小于hashCode的空间,所以就会出现hashCode不同,但是hash值相同,这就是哈希冲突。

为了解决哈希冲突,HashMap分别采用了以下方式:

  1. 采用拉链法链接拥有相同hash值的数据。
  2. 通过扰动函数来降低发生哈希冲突的概率,使数据分布更加均匀。
  3. 采用红黑树的数据结构,提高了搜索效率

HashMap和HashTable的区别

从线程安全性的角度来说,HashMap是线程不安全的,而HashTable是线程安全的

从效率上来看,HashMap比HashTable效率更高一些,另外HashTable基本被淘汰了。

对null key和null value的支持:HashMap中,可以用null作为键,不过这是唯一的,也可以用null作为value。但是HashTable不支持null key,否则会抛出NullPointerException

HashMap初始容量是16,每日扩容都会扩大到原来的两倍。HashTable初始容量为11,每次扩容后都会扩容到2n+1。如果创建时给了初始容量,那么HashMap会扩充为2的幂次方大小,而HashTable会直接使用给定的大小。

从底层数据结构来看:HashMap采用拉链法解决哈希冲突,而且在JDK1.8中引入了红黑树,提高了搜索效率。HashTable没有这样的机制。

HashMap 和 HashSet 区别

HashMap是Map的实现类,而HashSet是Set的实现类。

HashMap存储的是键值对,而HashSet存储的是对象。

HashSet是基于HashMap实现的,HashSet的底层数据结构是HashMap,HashSet存储的对象,其实就对应着HashMap的key,而value则是默认的空对象。

HashMap用key来计算哈希值,而HashSet用对象来计算哈希值。

HashMap 和 TreeMap 区别

HashMap和TreeMap都继承自AbstractMap,但是TreeMap还实现了NavigableMap和SortedMap接口。

实现Navigable接口让TreeMap有了对集合内元素搜索的能力

实现Sorted接口让TreeMap有了对集合内的元素根据键值排序的能力。默认是按照key的升序,但是我们也可以自定义排序

相比于HashMap,TreeMap多了对集合内元素搜索以及对集合内元素自定义排序的能力。

HashMap 多线程操作导致死循环问题

主要原因在于并发下的 Rehash 会造成元素之间会形成一个循环链表。不过,jdk 1.8 后解决了这个问题,但是还是不建议在多线程下使用 HashMap,因为多线程下使用 HashMap 还是会存在其他问题比如数据丢失。并发环境下推荐使用 ConcurrentHashMap 。

HashMap 和 ConcurrentHashMap 的区别

从线程安全性来看,HashMap是非线程安全的,ConcurrentHashMap是线程安全的

从底层数据结构来看,在JDK1.8之前,HashMap的底层数据结构是数组+链表,ConcurrentHashMap的底层数据结构是Segment数组+HashEntry数组+链表;在JDK1.8之后,HashMap的底层数据结构是数组+链表/红黑树,当冲突链长度超过阈值就会转化为红黑树,ConcurrentHashMap的底层数据结构是Node数组+链表/红黑树,同样当冲突链长度超过阈值就会转化为红黑树。

HashMap允许null的key,而ConcurrentHashMap不允许

ConcurrentHashMap 和 Hashtable 的区别?

从底层数据结构来看,JDK1.7的ConcurrentHashMap底层采用segment数组+HashEntry数组+链表实现,JDK1.8的ConcurrentHashMap采用Node数组+链表/红黑树来实现,在冲突链长度达到阈值时,链表转化为红黑树。HashTable的底层数据结构和JDK1.8之前的HashMap类似,是数组+链表,数组是HashTable的主体,链表则是为了解决哈希冲突存在的。

从二者实现线程安全的方式来看。JDK1.7的ConcurrentHashMap对整个桶数组进行了分段,没一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率,默认是分配16个segment。到了JDK1.8的时候已经完全摒弃了Segment的概念,而是直接用Node数组+链表/红黑树的数据结构来实现,对并发控制也进行了优化,使用synchronized和CAS来操作,整个看起来就像是优化过且线程安全的HashMap。HashTable是使用synchronized来保证线程安全,效率非常低下,当一个线程访问同步方法时,可能会进入阻塞或轮询状态。

ConcurrentHashMap 底层具体实现知道吗?实现原理是什么?

在JDK1.7中,ConcurrentHashMap底层数据结构是segment数组+HashEntry数组+链表实现的,一个ConcurrentHashMap包含一个Segment数组,Segment和HashMap结构类似,是基于HashEntry数组+链表实现的。ConcurrentHashMap将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程访问一个数据段时,其它段的数据仍可以被其它线程访问,提高了并发度。Segment是一种可重入锁ReentrantLock,当对HashEntry数组的数据进行修改时,首先要获得Segment锁。

在JDK1.8中,放弃了Segment的设计,取而代之的是Node+synchronized+CAS来保证并发安全。synchronized只锁定当前链表或红黑树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。

博客原文地址

每日面试题打卡(容器篇)——Day12
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九天漩女

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值