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.mfbz.cn/a/176105.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

代码文档浏览器 Dash mac中文版软件特色

Dash mac是一个基于 Python 的 web 应用程序框架,它可以帮助开发者快速构建数据可视化应用。Dash 的工作原理是将 Python 代码转换成 HTML、CSS 和 JavaScript,从而在浏览器中呈现交互式的数据可视化界面。Dash 提供了一系列组件,包括图表、表…

HarmonyOS ArkTS语言,运行Hello World(一)

一、下载与安装DevEco Studio 在HarmonyOS应用开发学习之前,需要进行一些准备工作,首先需要完成开发工具DevEco Studio的下载与安装以及环境配置。 进入DevEco Studio下载官网,单击“立即下载”进入下载页面。 DevEco Studio提供了Windows…

动态规划求 x 轴上相距最远的两个相邻点 java 代码实现

如图为某一状态下 x 轴上的情况,此时 E、F相距最远,现在加入一个点H,如果H位于点A的左边的话,只需要比较 A、H 的距离 和 E、F 的距离;如果点H位于点G的右边,则值需要比较 G、H 的距离 和 E、F 的距离&…

Docker安装Rabbitmq3.12并且prometheus进行监听【亲测可用】

一、安装Rabbitmq 下载镜像: docker pull rabbitmq:3.12-management 安装镜像: docker run -id --restartalways --namerabbitmq -v /usr/local/rabbitmq:/var/lib/rabbitmq -p 15692:15692 -p 15672:15672 -p 5672:5672 -e RABBITMQ_DEFAULT_USERgu…

在线接口测试工具fastmock使用

1、fastmock线上数据模拟器 在平时的项目测试中,尤其是前后端分离的时候,前端人员需要测试调用后端的接口,这个时候会出现测试不方便的情况。此时我们可以使用fastmock平台在线上模拟出一个可以调用的接口,方便前端人员进行数据测…

linux服务器安装gitlab

一、安装gitlab sudo yum install curl policycoreutils-python openssh-server openssh-clients sudo systemctl enable sshd sudo systemctl start sshd sudo firewall-cmd --permanent --add-servicehttp curl https://packages.gitlab.com/install/repositories/gitla…

OpenAI乱局幕后大佬浮出水面:Quora联合创始人

丨划重点 ● Quora德安杰洛在过去的周末积极游说圈内科技领袖出任OpenAI首席执行官。 ● 在奥特曼与OpenAI董事会关于重返公司的谈判中,德安杰洛是真正的主角。 ● Quora前员工透露,德安杰洛性格倔强,很难被说服。 ● Quora之前开发了人工…

c++ 谓词

1. 一元谓词 #include <iostream> #include<vector> #include<algorithm>using namespace std;class CreaterFive{ public:bool operator()(int val){return val>5;} };int main() {vector<int> vec;for(int i0; i<10; i){vec.push_back(i);}ve…

QML22、常规组件Page

Page是一个容器控件,可以方便地向页面添加页眉和页脚项。 title : string 此属性保存页面标题。 header : Item 此属性保存页眉项。标题项被定位到顶部,并调整大小为页面的宽度。缺省值为空。 注意:指定一个ToolBar, TabBar,或DialogButtonBox作为页眉会自动将各自的ToolBar…

使用hping3和wrk模拟泛洪

一、hping3 1、syn随机ip泛洪 hping3 --flood -S --rand-source -p 端口 目标ip hping3 -c 10000 -d 120 -S -p 80 --flood --rand-source 192.168.112.130​说明&#xff1a; -c 100000 packets 发送的数量 -d 120 packet的大小 -S 只发送syn packets -p 80 目标端口&am…

GNU工具链

1. GNU介绍 工具链典型的例子就是GNU工具链。 GNU工具链是由GNU项目产生的各种编程工具的集合&#xff0c;用于开发应用程序与操作系统。 GNU工具链在针对嵌入式系统的Linux内核、BSD及其它软件的开发中起着至关重要的作用。 GNU工具链中的部分工具也被Mac OS X, Microsoft W…

Redis篇---第十四篇

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

【人生苦短,我学 Python】(1)初识 Python

目录 1. 简述2. 什么是 Python&#xff1f;3. 面向对象简述3.1 面向过程3.2 面向对象3.3 面向对象的主要优点3.4 面向对象的基本概念3.5 面向对象程序设计 4. Python语言的版本和解释器5. Python 编程工具6. Python 的三种编程方式7. 简单的 Python 程序8. 高级一点的 Python 程…

15位、7位可控字符下的任意命令执行

可控字符串 长度受限情况下 Getshell

【OpenCV实现图像:使用OpenCV进行物体轮廓排序】

文章目录 概要读取图像获取轮廓轮廓排序小结 概要 在图像处理中&#xff0c;经常需要进行与物体轮廓相关的操作&#xff0c;比如计算目标轮廓的周长、面积等。为了获取目标轮廓的信息&#xff0c;通常使用OpenCV的findContours函数。然而&#xff0c;一旦获得轮廓信息后&#…

基于STM32的电子时钟(论文+源码)

1. 系统设计 电子时钟是一种广泛使用的工具&#xff0c;其可以帮助人们准确掌握时间&#xff0c;本课题基于STM32的电子时钟系统的设计&#xff0c;在功能上设计如下&#xff1a; 具有电子时钟的基本功能&#xff0c;显示年月日&#xff0c;时分秒等基本信息&#xff1b;可以…

经典双指针算法试题(二)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、有效三角形的个数1、题目讲解2、讲解算法原理3、代码实现 二、查找总价格为目标值的两个商…

JavaDS —— 初识集合框架 + 时间/空间复杂度

目录 1. 初识集合框架 1.1 集合框架的初识 1.2 什么是数据结构&#xff1f; 2. 时间与空间复杂度 2.1 时间复杂度 2.2 大O的渐进表示法 2.3 常见时间复杂度计算举例 2.4 空间复杂度 1. 初识集合框架 1.1 集合框架的初识 什么叫集合&#xff1f;什么叫框架&#xff1f;什么又叫集…

unity自制循环匀速动画

动画制作&#xff0c;有循环匀速要求时&#xff0c;需要调节Curves&#xff0c;将其节点的Tangent改为Linear

在建立 OkHttp3 Client 时设置超时时间

这里写目录标题 一. 前言二. 导入mavengradle 三. 设置超时时间 一. 前言 OkHttp是一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司开发。OkHttp3是Java和Android都能用&#xff0c;Android还有一个著名网络库叫Volley&#xff0c;那个只有Andro…