面试宝典之HashMap

HashMap

JDK1.8对HashMap进行了优化。本章聊一聊优化内容。

  • 数据结构:数组+链表——>数组+链表+红黑树
  • put方法:头插法(多线程有一个循环链表的问题)——>尾插法
  • 扩容机制
  • 链表红黑树相互转换

HashMap数据结构:

JDK1.8之前:数组+链表。
JDK1.8及之后:数组+链表+红黑树。

为什么引入红黑树?
因为如果链表太长,则会导致遍历的效率低下。
引入红黑树可以提高遍历的效率。

HashMap的put方法(jdk1.7)

当向一个hashmap中put一个键值对时,

  1. 对key进行hash,得到所属table数组的下标。
  2. 接着判断数组当前下标位置是否为空?若为空,则把当前节点当头节点。
  3. 如果不为空,则开始遍历链表,依次equals比较。
  4. 如果有相同的key,则用当前的value替代之前的value。
  5. 如果未找到相同的key,则使用头插法插入。

HashMap的put方法(jdk1.8)

向一个hashMap中put一个键值对。

  1. 对key进行hash,得到所属table数组的下标。
  2. 接着判断数组当前下标位置是否为空?若为空,则把当前节点当成头节点。
  3. 如果不为空,则开始遍历链表,依次equals比较。
  4. 如果有相同的key,则用当前的value替代之前的value。
  5. 如果未找到相同的key,则使用尾插法插入。

HashMap的循环链表问题(jdk1.7)

  1. 因为jdk1.7的hashMap是头插法,所以在扩容转移元素的时候会使链表发生反转。
  2. 在多线程的情况下,两个线程同时触发扩容。
  3. 线程a,b都进入扩容状态,分别都会有一个e和e.next 用来遍历链表转移元素。
  4. 当a线程完成扩容,链表已经反转了,但是b还未遍历完链表,此时b线程的e.next指向的元素转移到了e所指元素之前,然后就形成了一个循环链表。

扩容机制

阈值=容量*负载因子。
当hashMap的元素个数大于阈值时,会触发扩容。

HashMap1.8的红黑树和链表转换

  • 当数组长度大于64且链表长度大于8则会把链表转换成红黑树。
  • 当红黑树元素的个数小于6则会把红黑树转换成链表。

ConcurrentHashMap

ConcurrentHashMap 是HashMap的线程安全版本。

jdk1.7和1.8的区别。

JDK7中ConcurrentHashMap是通过ReentrantLock+CAS+分段思想来保证的并发安全的,在JDK7的ConcurrentHashMap中,首先有一个Segment数组,存的是Segment对象,Segment相当于一个小HashMap,Segment内部有一个HashEntry的数组,也有扩容的阈值,同时Segment继承了ReentrantLock类,同时在Segment中还提供了put,get等方法,比如Segment的put方法在一开始就会去加锁,加到锁之后才会把key,value存到Segment中去,然后释放锁。

同时在ConcurrentHashMap的put方法中,会通过CAS的方式把一个Segment对象存到Segment数组的某个位置中。

同时因为一个Segment内部存在一个HashEntry数组,所以和HashMap对比来看,相当于分段了,每段里面是一个小的HashMap,每段公用一把锁,同时在ConcurrentHashMap的构造方法中是可以设置分段的数量的,叫做并发级别concurrencyLevel.

JDK8中ConcurrentHashMap是通过synchronized+cas来实现了。在JDK8中只有一个数组,就是Node数组,Node就是key,value,hashcode封装出来的对象,和HashMap中的Entry一样,在JDK8中通过对Node数组的某个index位置的元素进行同步,达到该index位置的并发安全。同时内部也利用了CAS对数组的某个位置进行并发安全的赋值。

JDK8的ConcurrentHashMap为什么使用Synchronized 来上锁?

JDK7中使用ReentrantLock来加锁,因为JDK7中使用了分段锁,所以对于一个ConcurrentHashMap对象而言,分了几段就得有几个ReentrantLock对象,表示得有对应的几把锁。

而JDK8中使用synchronized关键字来加锁就会更节省内存,并且jdk也已经对synchronized的底层工作机制进行了优化,效率更好。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值