HashMap知识点总结

文章目录

    • HashMap
    • ConcurrentHashMap
    • 线程安全问题

HashMap

1、null作为key只能有一个,作为value可以有多个

2、容量:

  • 1.7:默认16
  • 1.8:初始化并未指定容量大小,第一次put才初始化容量

3、负载因子 默认0.75,扩容触发:元素个数 > 容量 * 负载因子,扩容

4、哈希算法:

  • 首先获取key的哈希值h
  • 将h高16位和低16为进行异或运算,让高16位参与hash,减少哈希冲突

5、底层结构:

  • 1.7:数组+链表
  • 1.8:数据+链表/红黑树

为什么引入链表

HashMap底层是数组,当进行put操作时,会进行hash计算,判断元素位置。当多个元素在同一个数组位置时,会引起hash冲突,因此引入链表,解决hash冲突

为什么jdk1.8会引入红黑树

当链表长度大于8时,遍历查找效率较慢,故引入红黑树

链表长度>8,且数组长度>64,才变成红黑树

为什么一开始不就使用红黑树?

红黑树相对于链表维护成本大,红黑树在插入新数据之后,可能会通过左旋、右旋、变色来保持平衡,造成维护成本过高,故链路较短时,不适合用红黑树

HashMap的底层数组取值的时候,为什么不用取模,而是&

i = (n - 1) & hash,计算机运算时,&比取模运算快

数组的长度为什么是2的次幂

1、减少hash冲突

数据均匀分布,可以减少hash冲突,所以使用hash%n可以最大程度的平均分配。当n为2的次幂时,(n-1)&hash=hash%n

2、&运算速度比%快,Java中快10倍左右

3、保证索引值在capacity中不会超出数组长度

如果指定数组的长度不为2的次幂,就破坏了数组的长度是2的次幂的这个规则吗

不会的,HashMap 的tableSizeFor方法做了处理,能保证n永远都是2的次幂

tableSizeFor(initialCapacity)

6、put方法流程:

  1. 计算key的哈希值

  2. 判断数组是否为空

    1. 是:扩容,进行初始化
    2. 否:查找哈希值对应的数组下标
  3. 判断下标元素是否为空

    1. 是:创建新元素
    2. 否:步骤4
  4. 判断底层结构是否是红黑树

    1. 是:执行红黑树新增逻辑
    2. 否:说明是链表结构,新增元素到链表尾
  5. 判断链表属性,链表长度是否≥8,数组长度是否≥64

    1. 是:链表转红黑树,判断size≥threshold,是执行扩容
    2. 否:执行扩容逻辑

7、HashMap为什么线程不安全

  1. HashMap扩容的时候,是会将原先的链表迁移至新的链表数组中,在迁移过程中多线程情况下会有造成链表的死循环情况(JDK1.7之前的头插法)
  2. 在多线程插入的时候也会造成链表中数据的覆盖导致数据丢失

8、解决哈希冲突的方法

  1. 链地址法:冲突值链接成一个链表,HashMap
  2. 线性探测法:发生冲突,继续向下遍历,直到找到空闲内置T,hreadLocal
  3. 再哈希法:冲突后,再使用一个新的哈希算法计算,直到不发生冲突

9、扩容:

1.7:

size>=threshold,且新建的Entry刚好落在一个非空的桶上,扩容为2倍容量

threshold=loadFactor*capacity

扩容过程:先计算新的容量和threshold,再创建一个新hash表,最后将旧hash表中元素rehash到新的hash表中

1.8:(与1.7的区别)

  1. 第一次调用put方法,初始化扩容为16
  2. 插入数据时size>=threshold就扩容为原来的2倍(不管有没有空位都扩容,1.7是没有空位才扩容)
  3. 使用尾插法扩容(1.7是头插法扩容)

计划用HashMap存1k条数据,构造时传1000会触发扩容吗

HashMap 初始容量指定为 1000,会被 tableSizeFor() 调整为 1024;但是它只是表示 table 数组为 1024;负载因子是0.75,扩容阈值会在 resize() 中调整为 768(1024 * 0.75)会触发扩容,如果需要存储1k的数据,应该传入1000 / 0.75(1333)。tableSizeFor() 方法调整到 2048,不会触发扩容

用HashMap存1w条数据,构造时传10000会触发扩容吗

当我们构造HashMap时,参数传入进来 1w,经过 tableSizeFor() 方法处理之后,就会变成 2 的 14 次幂 16384负载因子是 0.75f,可存储的数据容量是 12288(16384 * 0.75f)完全够用,不会触发扩容

ConcurrentHashMap

1、存储结构

1.7:segment数组+链表

segment默认16,默认最多支持16个线程并发,并且segment初始化后不能更改

1.8:Node数组+链表/红黑树

2、锁:

1.7:分段锁

1.8:Synchronized+CAS,锁粒度更小

线程安全问题

1、HashMap线程不安全

  1. HashMap扩容的时候,是会将原先的链表迁移至新的链表数组中,在迁移过程中多线程情况下会有造成链表的死循环情况(JDK1.7之前的头插法)
  2. 在多线程插入的时候也会造成链表中数据的覆盖导致数据丢失

线程安全:HashTable、ConcurrentHashMap

2、HashTable线程安全

问题:实现线程安全的代价大,所有可能产生竞争的方法里都加上了synchronized,导致在出现竞争时,只能一个线程进行操作,其他线程都需要阻塞等待当前取到锁的线程执行完成

3、ConcurrentHashMap线程安全

1.7:分段锁,对每一个segment加锁

数组有大数组segment,小数组HashEntry,HashEntry的每个元素是一个链表,加锁是通过给Segment加ReentrantLock重入锁来保证线程安全

img

get():HashEntry中采用volatile来修饰HashEntry的当前值和next元素的值,所以在获取数据时不需要加加锁,大大提高了执行效率

put():先尝试获取锁(tryLock()),如果获取失败,说明存在竞争,那么通过scanAndLockForPut()方法自旋,当自旋次数达到MAX_SCAN_RETRIES时会执行阻塞锁,直到获取锁成功

1.8:采用CAS+synchronized的方法来保证线程安全

put():

1、计算出hash值

2、判断当前数据结构是否从未放过数据,即是否未初始化,为空则先执行初始化

3、通过key的hash判断当前位置是否为null

4、如果当前位置为null,则通过CAS写入,如果CAS写入失败,通过自旋保证写入成功

5、当前hash值等于MOVED(-1)时,需要进行扩容

6、当上面的内容都不满足时,采用synchronized阻塞锁,来将数据进行写入

7、如果数量大于TREEIFY_THRESHOLD(8),需要转化为红黑树

get():

1、根据key的hash寻找到具体的位置

2、如果是红黑树就按照红黑树的方式去查找数据

3、如果是链表就按照链表的方式去查找数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/158754.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NOSQL----redis的安装和基础命令

redis是什么 1.redis-------非关系型数据库 redis是非关系数据库的一种,也称为缓存型数据库。 非关系型数据库和关系型数据库 1.关系型数据库 关系型数据库是一个结构化的数据库,记录方式是行和列(列:声明对象,行&am…

探索分销小程序商城开发和搭建

在数字化时代,小程序已经成为了企业营销的重要工具。其中,分销小程序商城以其独特的优势,吸引了众多企业的关注。下面给大家介绍如何开发分销小程序商城,以及小程序分销搭建的流程。 首先,我们需要明确什么是分销小程…

中国信息通信研究院发布《中国金融科技生态白皮书》(2023)

加gzh“大数据食铁兽”,回复“20231122”,获取材料完整版 导读 本白皮书是中国信息通信研究院连续第六年针对金融科技领域的跟踪研究成果,聚焦过去一年来国内外金融科技领域新的发展情况,重点分析了中国金融科技产业、技术、市…

七牛云产品使用介绍之CDN篇

上一篇介绍了七牛云的Kodo对象存储,并用Java SDK实现将本地文件上传到bucekt,接下来是对CDN产品的介绍 CDN(内容分发网络):通过多级缓存实现对Kodo中的资源或者自己网站的资源的加速访问,让你的系统更快更强…

AMEYA360:村田首款1608M尺寸/100V静电容量1µF的MLCC实现商品化

株式会社村田制作所成功开发了用于基站、服务器和数据中心48V线路的多层陶瓷电容器“GRM188D72A105KE01”并已量产。该产品在1608M(1.60.8mm)尺寸、100V的额定电压下可实现1μF的超大静电容量(村田调查数据,截至2023年11月20日)。目前可向村田申请免费样品。 随着5G…

NOIP2015提高组第二轮T1:能量项链

题目链接 [NOIP2006 提高组] 能量项链 题目描述 在 Mars 星球上,每个 Mars 人都随身佩带着一串能量项链。在项链上有 N N N 颗能量珠。能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子&#xff0…

网络和Linux网络_4(应用层)序列化和反序列化(网络计算器)

目录 1. 重新理解协议 2. 网络版本计算器 2.1 前期封装 Log.hpp sock.hpp TcpServer.hpp 第一次测试(链接) 2.2 计算器实现 第二次测试(序列化和反序列化) 第三次测试(客户端字节流) CalServer.cc CalClient.cc 3. 守护进程 3.1 守护进程和前后台进程 3.1 变成…

数组扩展方法(一)

Array.prototype.forEach MDN解释forEach()方法是对数组的每个元素执行一个给定的函数,换句话来说就是在调用forEach()方法的时候,需要传入一个回调函数callback,循环每个数组内部元素时都会执行一次传入的回调函数callback forEach()方法的…

AUTOSAR实战篇:基于ETAS工具链的信息安全协议栈集成指南

AUTOSAR实战: 基于ETAS工具链的信息安全协议栈集成指南 前言 小T出品,必是精品! 手把手带你集成信息安全协议栈,你值得拥有! 正文 随着汽车信息安全的不断发展与完善,其在汽车电子领域如智能驾驶(ADAS),智能座舱等方向上不断被重视起来,越来越多的Tier1,主机厂都在全面…

LeetCode算法心得——爬楼梯(记忆化搜索+dp)

大家好,我是晴天学长,第二个记忆化搜索练习,需要的小伙伴可以关注支持一下哦!后续会继续更新的。💪💪💪 1)爬楼梯 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或…

Redis主从复制,哨兵和Cluster集群

主从复制: 主从复制是高可用Redis的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份(和同步),以及对于读操作的负载均衡和简单的故障恢复。 缺陷:故障恢复无法自动化…

C# ReadOnlyRef Out

C# ReadOnly ReadOnly先看两种情况1.值类型2.引用类型 结论 Ref Out ReadOnly官方文档 ReadOnly 先看两种情况 1.值类型 当数据是值类型时,标记为Readonly时,如果再次设置值,会提示报错,无法分配到只读字段 public class A {pri…

基于Springboot的美容院管理系统(有报告)。Javaee项目,springboot项目。

演示视频: 基于Springboot的美容院管理系统(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构&a…

Redis(事务和持久化)(很重要!)

事务的定义: Redis中的事务是指一组命令的集合,这些命令可以在一个原子操作中执行。在Redis中,可以使用MULTI命令开始一个事务,然后使用EXEC命令来执行事务中的所有命令,或者使用DISCARD命令来取消事务。事务可以确保…

爬取春秋航空航班信息

一、使用fiddler爬取小程序春秋航空航班信息 使用Fiddler爬取春秋航空微信小程序(手机上由于网络问题,无法进入,使用电脑版) 搜索航班信息 搜索记录 使用Fiddler查找url(没有得到有效url) 继续查找,发现航班信息列…

数据结构:二叉树(初阶)

朋友们、伙计们,我们又见面了,本期来给大家解读一下二叉树方面的相关知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏:C语言:从入门到精通 …

振南技术干货集:制冷设备大型IoT监测项目研发纪实(3)

注解目录 1.制冷设备的监测迫在眉睫 1.1 冷食的利润贡献 1.2 冷设监测系统的困难 (制冷设备对于便利店为何如何重要?了解一下你所不知道的便利店和新零售行业。关 于电力线载波通信的论战。) 2、电路设计 2.1 防护电路 2.1.1 强电防护…

LeetCode:2304. 网格中的最小路径代价(C++)

目录 2304. 网格中的最小路径代价 题目描述: 实现代码: dp(dp有很多相似的经典题目,比较简单,不再给出解析) 2304. 网格中的最小路径代价 题目描述: 给你一个下标从 0 开始的整数矩阵 grid …

Redis篇---第十四篇

系列文章目录 文章目录 系列文章目录前言一、为什么Redis的操作是原子性的,怎么保证原子性的?二、了解Redis的事务吗?四、Redis 的数据类型及使用场景前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男…

前端js调取摄像头并实现拍照功能

前言 最近接到的一个需求十分有意思,设计整体实现了前端仿 微信扫一扫 的功能。整理了一下思路,做一个分享。 tips: 如果想要实现完整扫一扫的功能,你需要掌握一些前置知识,这次我们先讲如何实现拍照并且保存的功能。 一. windo…