一文搞懂HashMap实现原理

本文深入探讨HashMap的数据结构,包括数组、链表和红黑树。详细阐述了解决哈希冲突的开放定址法和拉链法。重点分析了HashMap的线程不安全问题,举例说明了并发插入可能导致的数据覆盖,并提出了使用ConcurrentHashMap作为线程安全的解决方案。此外,还讨论了初始化HashMap的最佳容量,以及HashMap的重要属性如负载因子和阈值。
摘要由CSDN通过智能技术生成
Hey,我是寅贝勒,后端开发一枚😜,欢迎来我的个人网站 www.ly-zone.cloud 一起学习交流~

数据结构: 数组+链表+红黑树

解决哈希冲突的主要方法:

  • 开放定址法(线性探查法、线性补偿探测法(
  • 拉链法(单链表)

它根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 HashMap最多只允许一条记录的键为null,允许多条记录的值为null。HashMap非线程安全,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap
在这里插入图片描述
为什么说hashmap是线程不安全的
如果线程A和线程B同时进行put操作,刚好这两条不同的数据hash值一样,并且该位置数据为null,接下来线程A、B本应该都会进入源码631行进行执行操作,如果此时,线程A进入后还未进行数据插入时挂起了,没有获取到CUP时间片,而线程B正常执行,从而B正常插入数据,放入一个元素,然后执行完了B走了,此时轮到线程A获取CPU时间片,在挂起前已经执行了源码630行,线程A将不用再进行hash判断了,而是直接执行源码631行。杯具来了:线程A会把线程B插入的数据给覆盖,发生线程不安全。针对这个情况怎么处理呢,可以直接对整个方法加锁,用synchronized,但性能损耗太大。官方推荐使用ConcurrentHashMap,采用分段锁机制,即避免了线程不安全,也极大照顾了性能损耗

如果确定只装载100个元素,new HashMap(?)多少是最佳的

重点关注tableSizeFor(initialCapacity),这才是真正的容量,结果是返回一个不小于传入参数并且最近的一个2的n次方的值,扩容阈值threshold = size * 0.75,言外之意就是当元素put到第96个时,就会再次进行resize()方法,而resize()方法是非常耗时间的,结合我们实际情况进行一次resize()方法只为了多放4个元素,这样的损耗显然是不适合的;所以,综上所述,个人觉得初始化最好的应该是256

属性

  • loadfactor:负载因子,默认为0.75
  • threshold:所能容乃的键值对的临界值=数组长度 * 负载因子
  • modcount:记录hashmap内部结构发生变化的次数
    在这里插入图片描述

更多技术博客、答疑、交流,欢迎关注我的微信公众号:寅贝勒

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

寅贝勒

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

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

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

打赏作者

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

抵扣说明:

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

余额充值