HashMap源码分析

HashMap的数据结构
在这里插入图片描述
点进Entry
里面有个Entry<K,V> next,它是个链表
HashMap整体来看是个数组,每个数组对应的是
在这里插入图片描述
HashMap就是通过这个next来解决key的hash冲突,通过链表的方式解决hash冲突,而这个链表指的就是LinkedList
HashMap源码里面有四个常量
第一个常量:map的默认长度 2^4
在这里插入图片描述
第二个常量:map的最大允许长度 2^30
在这里插入图片描述第三个常量:加载因子 0.75
在这里插入图片描述

如果数组长度为16,16*0.75=12,那么到了12的时候,数组就会扩容2倍
HashMap的put方法
在这里插入图片描述
第一次向map中添加kv
在这里插入图片描述
判断key值是否为空,是可以为空的,但是map会将空值放入链表的首位
在这里插入图片描述
addEntry这个方法,把key为null的放入链表首位,hash值为0
在这里插入图片描述
如果key不为空,会将key做hash处理,得到int数据值,经过大量算法,例如泊松算法计算得出的
在这里插入图片描述
indexFor保证了数组下标永远不会越界,计算出来的hash值会均匀的分布在每个节点上,增加了效率
key的冲突解决(hash碰撞)
在这里插入图片描述
如果key的hash值一样,equals也一样,就会产生hash冲突
使用链表解决hash冲突,数组有个next,来解决

HashMap的扩容 resize
点进addEntry,如果长度大于阈值进行扩容,是以前数组的两倍
在这里插入图片描述
会将就的值 重新计算hash的值,再放入新的Entry中,这就导致了hashmap的性能相对较低
在这里插入图片描述
hashmap的get方法
在这里插入图片描述
如果key为null,直接return
get再去值的时候,如果key不为null,会先去计算key的hash值,计算他的位置(数组的位置),和indexFor结合,不用去遍历,提高了查询的效率,这个for循环的作用就是遍历链表,先去用hash判断key的位置,用用equals方法,去定位要取的值
在这里插入图片描述
总结:
先用hash定位数组的位置,再去遍历链表,遍历链表的时候,先去用hash判断key的位置,用用equals方法,去定位要取的值
HashMap的不足
Entry放在成员位置,在多线程的情况下,两个map同时向Entry里面存值,可能会导致数组长度不一样,产生线程安全问题
HashMap和HashTable的区别
在这里插入图片描述
怎么解决HashMap的线程安全问题
javaUtils里面的concurrent这个包对我们简单常用的数据类型做了一个线程同步、线程安全,这个类下面的所有的成员属性和方法都是线程安全的
在多线程条件下,容易导致死循环,具体表现为CPU使用率100%。因此多线程环境下保证 HashMap 的线程安全性,主要有如下几种方法:
1.替换成Hashtable,Hashtable通过对整个表上锁实现线程安全,因此效率比较低
2.使用Collections类的synchronizedMap方法包装一下。方法如下:
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) 返回由指定映射支持的同步(线程安全的)映射
3.使用ConcurrentHashMap,它使用分段锁来保证线程安全

通过前两种方式获得的线程安全的HashMap在读写数据的时候会对整个容器上锁,而ConcurrentHashMap并不需要对整个容器上锁,它只需要锁住要修改的部分就行了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值