关于HashMap

hashMap是一个用key-value键值对的集合,每一个键值对都是一个Entry,这些键值对分散存储在一个数组中,这个数组就是HashMap的主干,HashMap数组每一个元素都是null。HashMap默认的初始长度是16,每次自动或者手动扩展时,必须是2的幂。

在HashMap中,使用的最多的是:put和get。
Put的原理:
当我们调用了PUT的时候,HashMap会通过设置的key值进行哈希函数计算,通过计算出的结果值来确定插入的位置:
Index = hash(“key”)
但是HashMap的长度也是有限的,当插入的Entry的越来越多的时候,再完美的hash也会出现重复的index,这时候HashMap就采用链表的形式来解决这个问题,HashMap数据的每一个元素不止是一个Entry对象,也是一个链表头,每一个Entry对象都会通过next指向它下一个Entry的节点,当新来的Entry映射到冲突的数组位置时,只需要插入到对应的链表即可,新来的Entry节点插入链表时,使用的是头插法。
Get的原理
当我们调用GET的时候,同样是进行了hash函数对key的计算,如果计算的位置匹配到多个Entry,这时就需要顺着对应的链表头节点一个个的往下找,之所以在Put时使用的时头插法,是因为设计者认为后插入的Entry被查找的可能性更大。

为什么初始长度要是16,扩展必须是2的幂?
这是为了实现一个尽量均匀分布的hash函数,通过key的hashCode值做了一些运算,因为长度16或2的幂,length-1 的值所有的二进制全为1,这种情况下,index的结果等同于hashCode后几位的值。只要输入的HashCode本身分布均匀,Hash算法的结果就是匀的。
公式:index = hashCode(key) & length-1
为了实现高效的hash算法,HashMap的发明者采用了位运算的方式。

HashMap是非线程安全的,当经过多次元素插入,是的HashMap达到一定的饱和度时,key映射位置发送冲突的几率逐渐提高,这时候HashMap需要扩展它的长度,也就是resize。衡量是否要进行resize的条件:
HashMap.size >= capacity(当前长度) * loadFactor(负载因子,默认为0.75f)
HashMap的resize包含扩容和rehash两个步骤,rehash在并发的情况下可能会形成链表环,当出现链表环时,调用get的恰好在链表环的位置,程序将会进入死循环。

ConcurrentHashMap:
ConcurrentHashMap采用了一种叫Segment的概念,Segment本身就相当于一个HashMap对象。和HashMap一样,Segment包含一个HashEntry数组,数组中的每一个HashEntry既是一个键值对,也是一个链表的头节点。可以说ConcurrentHashMap是一个二级哈希表。在一个总的哈希表下面,有若干个子哈希表。使用这种设计的优势就是采用了”锁分段技术“,每一个segment都是读写操作高度自治的,segment之间互不影响,不同segment可以并发写入,同一segment可以并发读写,但是同一segment并发写入会被阻塞,因为segment写入是需要上锁的。

Get方法:
1.为输入的Key做Hash运算,得到hash值。
2.通过hash值,定位到对应的Segment对象
3.再次通过hash值,定位到Segment当中数组的具体位置。

Put方法:
1.为输入的Key做Hash运算,得到hash值。
2.通过hash值,定位到对应的Segment对象
3.获取可重入锁
4.再次通过hash值,定位到Segment当中数组的具体位置。
5.插入或覆盖HashEntry对象。
6.释放锁。

ConcurrentHashMap的Size方法是一个嵌套循环,大体逻辑如下:
1.遍历所有的Segment。
2.把Segment的元素数量累加起来。
3.把Segment的修改次数累加起来。
4.判断所有Segment的总修改次数是否大于上一次的总修改次数。如果大于,说明统计过程中有修改,重新统计,尝试次数+1;如果不是。说明没有修改,统计结束。
5.如果尝试次数超过阈值,则对每一个Segment加锁,再重新统计。
6.再次判断所有Segment的总修改次数是否大于上一次的总修改次数。由于已经加锁,次数一定和上次相等。
7.释放锁,统计结束。

程序员小灰公众号读后总结:https://mp.weixin.qq.com/s/1yWSfdz0j-PprGkDgOomhQ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值