hashmap和ConcurrentHashMap详解(对比1.8前后)

hashmap

HashMap是一个用于存储Key-Value键值对的集合,每一个键值对对象叫做Entry,这些键值对(entry)储存在一个数组中。

对于hashmap,我们最常用的就是get和put方法,那么这两个方法具体做了什么事情?
put方法: 比如调用hashmap.put(name,tang); 首先会调用hash函数来决定键值对插入数组的索引,假设算出来的索引为3.在这里插入图片描述
但是当多次put之后,难免会出现又一个键值对,hash函数后索引也为3.这就是哈希冲突。

这个时候,我们采用链表来解决问题,也就是说,hashmap的底层是链表加上数组。每个Entry对象也是链表的头节点,它的next指向下一个Entry对象,也就是哈希冲突的对象。(tip:采用头插法插入,因为默认后插入的键值对有更大几率被使用

在这里插入图片描述
 
get方法:它首先会对key做一次hash映射,然后对得到的索引进行查找,按照链表从头到尾,比对key值。

hash map的初始值是多少,又是如何进行哈希运算的?
hashmap的默认初始值为16,每次进行手动初始化,或者自动扩容时都是2的幂次方。

hashmap没有采用简单的hashcode(key)%length的取模运算,因为它的效率底下。而采用了index = HashCode(Key) & (Length - 1) 这种位运算的方式。这种方式不仅高效,而且最大化的使得到的索引值均匀分布。

这也是为什么要求值必须是2的幂次方,因为只有此时length-1得到的二进制数是全1,最后的结果就是hashcode值的最后几位,这样能使得到的索引值均匀分布。

 

jdk1.8之后

在jdk1.8之后,hashmap的底层加入的红黑树结构,也就是底层变成了数组,链表和红黑树。它主要是为了防止一种极端情况,也就是当所以的hash运算后的索引都是一个值,就会使某一个数组下标的链表过长,降低效率。而加入了红黑树后,当我们的链表长度达到8后就会使链表变成红黑树结构,将最坏情况下的性能从O(n)降低成了O(lgn)。

此时完整的put方法
1.若hashmap未被初始化,就执行初始化操作。
2.对key进行hash取模运算,得到索引值。
3.若未发生碰撞就放入数组对应下标。
4.若发生碰撞,则以头插法插入链表。
5.链表长度超过8时,将链表结构转换为红黑树,当长度低于6时将红黑树变为链表。
6.若节点已经存在,就替换它
7.当数组内的键值对满了,也就是(16(默认初始化长度)*0.75(扩容因子))时,resize(扩容两倍后重排)

关于扩容的过程:主要是两步
1.创建一个新的Entry(1.8后改名为Node)数组,长度是原来的两倍。

2遍历原数组,将所有元素重新hash到新数组中。

 

ConcurrentHashMap

hashmap不是线程安全的,它可能产生环形链表(暂不深究),此时我们可以使用ConcurrentHashMap来保证线程安全。hashtable也可以保证线程安全,但它是建议保留的。并且它会锁住整个集合,性能低下。

早期的ConcurrentHashMap将整个集合拆分为segment,segment也是hashmap对象,所以ConcurrentHashMap的结构大概如下:
在这里插入图片描述
ConcurrentHashMap通过更细粒化的分为segment,只锁住一个segment来提高性能。

1.8之前的put方法过程:
1.对key做hash运算定位到segment对象。
2.获得可重入锁
3.再次hash运算得到数组中具体的位置
4.执行操作,释放锁(注意使用两次hash

1.8之后put方法的过程是
1.判断hash map是否被初始化,若未初始化,则进行初始化操作。
2.通过hash得到索引,若索引处没有Node对象,则用CAS进行添加,添加失败则重试。
3.如果索引处存在Node对象,则用synchornized锁住此元素,进行添加操作。
4.判断链表长度是否达到8,若是,则将链表转换为红黑树。

ConcurrentHashMap在jdk1.8之后相比以前有什么区别?
ConcurrentHashMap的锁更加细粒化了,早期是锁住整个segment,现在是锁住某个Node对象。现在是用CAS和synchornized来实现线程安全的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值