底层原理解析

2023-05-16

目录

HashMap底层原理:

ConcurrentHashMap 底层原理


HashMap底层原理:


1. HashMap概述
HashMap是一个散列桶(数组和链表),它存储的内容是键值对(key-value)映射
HashMap采用了数组和链表的数据结构,能在查询和修改方便继承了数组的线性查找和链表的寻址修改
HashMap是非synchronized,所以HashMap很快
HashMap可以接受null键和值,而Hashtable则不能(原因就是equlas()方法需要对象,因为HashMap是后出的API经过处理才可以)
put方法

  • 调用哈希函数获取Key对应的hash值,然后结合数组长度再计算其数组下标;

  • 如果没有出现哈希冲突,则直接放入数组;如果出现哈希冲突,则以链表的方式放在链表后面;

  • 如果链表长度超过阀值(TREEIFYTHRESHOLD==8),就把链表转成红黑树,链表长度低于6,就把红黑树转回链表;

  • 如果结点的key已经存在,则替换其value即可;

  • 如果集合中的键值对大于12,调用resize方法进行数组扩容。


get方法
计算需获取数据的hash值(计算过程跟put一样),计算存放在数组table中的位置(计算过程跟put一样),然后依次在数组,红黑树,链表中查找(通过equals()判断),最后再判断获取的数据是否为空,若为空返回null否则返回该数据

为什么使用红黑树而不用二叉树


之所以选择红黑树是为了解决二叉查找树的缺陷,二叉查找树在特殊情况下会变成一条线性结构(这就跟原来使用链表结构一样了,造成很深的问题),遍历查找会非常慢,而红黑树在插入新数据后可能需要通过左旋,右旋、变色这些操作来保持平衡,引入红黑树就是为了查找数据快,解决链表查询深度的问题,我们知道红黑树属于平衡二叉树,但是为了保持“平衡”是需要付出代价的,但是该代价所损耗的资源要比遍历线性链表要少,所以当长度大于8的时候,会使用红黑树,如果链表长度很短的话,根本不需要引入红黑树,引入反而会慢。

HashMap 扩容机制

①、table 数组大小是由 capacity 这个参数确定的,默认是16,也可以构造时传入,最大限制是1<<30;
②、loadFactor 是装载因子,主要目的是用来确认table 数组是否需要动态扩展,默认值是0.75,比如table 数组大小为 16,装载因子为 0.75 时,threshold 就是12,当 table 的实际大小超过 12 时,table就需要动态扩容;
③、扩容时,调用 resize() 方法,将 table 长度变为原来的两倍(注意是 table 长度,而不是 threshold)
④、如果数据很大的情况下,扩展时将会带来性能的损失,在性能要求很高的地方,这种损失很可能很致命。

HashMap负载因子初始值为什么是0.75?

当负载因子为1.0时,意味着只有当hashMap装满之后才会进行扩容,虽然空间利用率有大的提升,但是这就会导致大量的hash冲突,使得查询效率变低。

当负载因子为0.5或者更低的时候,hash冲突降低,查询效率提高,但是由于负载因子太低,导致原来只需要1M的空间存储信息,现在用了2M的空间。最终结果就是空间利用率太低。

总结
负载因子是0.75的时候,这是时间和空间的权衡,空间利用率比较高,而且避免了相当多的Hash冲突,使得底层的链表或者是红黑树的高度也比较低,提升了空间效率。
 

ConcurrentHashMap 底层原理

在这里插入图片描述

 

put() 方法的核心思想:由于其减小了锁的粒度,若 Hash 完美不冲突的情况下,可同时支持 n 个线程同时 put 操作,n 为 Node 数组大小,在默认大小 16 下,可以支持最大同时 16 个线程无竞争同时操作且线程安全

当 Hash 冲突严重时,Node 链表越来越长,将导致严重的锁竞争,此时会进行扩容,将 Node 进行再散列,下面会介绍扩容的线程安全性。总结一下用到的并发技巧

减小锁粒度:将 Node 链表的头节点作为锁,若在默认大小 16 情况下,将有 16 把锁,大大减小了锁竞争(上下文切换),就像开头所说,将串行的部分最大化缩小,在理想情况下线程的 put 操作都为并行操作。同时直接锁住头节点,保证了线程安全
使用了 volatile 修饰 table 变量,并使用 Unsafe 的 getObjectVolatile() 方法拿到最新的 Node
CAS 操作:如果上述拿到的最新的 Node 为 null,则说明还没有任何线程在此 Node 位置进行插入操作,说明本次操作是第一次
synchronized 同步锁:如果此时拿到的最新的 Node 不为 null,则说明已经有线程在此 Node 位置进行了插入操作,此时就产生了 hash 冲突;此时的 synchronized 同步锁就起到了关键作用,防止在多线程的情况下发生数据覆盖(线程不安全),接着在 synchronized 同步锁的管理下按照相应的规则执行操作
当 hash 值相同并 key 值也相同时,则替换掉原 value
否则,将数据插入链表或红黑树相应的节点
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

底层原理解析 的相关文章

随机推荐

  • Android Studio 控制台中文乱码,解决方案都在这里了,完美解决

    前言 Android Studio 如果不进行配置的话 xff0c 运行程序时控制台中文乱码问题会非常严重 xff0c 甚至影响我们对信息的获取和程序的跟踪 通过历年的开发经验 xff0c 在本文中我总结出四点用于解决控制台中文乱码问题的方
  • 【C/C++】中的__FILE__、__LINE__、#line、__func__关键字(预定义宏)

    c 43 43 11预先定义了一些标识符 xff0c 其实也就是宏 现在简单说几个 xff1a 1 FILE 用于指示本行语句所在源文件的文件名 xff0c 如下 xff08 test c xff09 xff1a include lt st
  • 视觉SLAM入门十四讲

    视觉SLAM入门十四讲 写在前面的话什么是视觉SLAM视觉SLAM中所使用的摄像头传感器单目摄像头双目摄像头深度摄像头 经典视觉SLAM框架 写在前面的话 考研期间迷上了SLAM xff0c 买来了高翔 张涛等著的 视觉SLAM十四讲 从理
  • px4源码编译指南

    px4源码编译指南 强烈推荐大家去看官网的英文文档 xff0c 国内的博客杂七杂八 xff0c 官网的中文也很久没有更新 xff0c 这几天自己踩了很多坑 xff0c 写个教程希望能帮助到大家 xff08 本文选用平台是pixhawk1 1
  • 敏捷开发:做一个合格的Scrum Master

    图片来源于网络 Scrum Master Beauty and Beast 在Scrum敏捷开发中有三种主要的角色 xff1a Product Owner xff08 产品负责人 xff0c 简称 34 PO 34 xff09 Scrum
  • 嵌入式软件:通过串口进行调试的一些思考和实践

    最近的工作还是改那坨代码 维护这摊东西也快要2年了 xff0c 好几次想重构它 xff0c 顺便整理一下 xff0c 不过我还是缺乏那种毅力 在这段时间里我还加了一些功能模块 xff0c 估计如果以后有新人接手这摊东西 xff0c 会抱怨这
  • 串口调试助手没有显示

    用cubeMX生成工程之后 xff0c 笔者写了下面两句话 xff08 向串口发送一个字符串 xff09 xff1a 但是 xff0c 打开调试工具怎么也接受不到数据 xff0c 魔术棒里面的 芯片型号 xff0c 调试 xff08 J L
  • vscode使用gitee

    vscode使用gitee 首先选择文件夹右键用vscode打开 然后打开vscode的终端 xff1a 在终端输入命令 xff1a xff08 每行命令输入完成之后记得敲回车 xff09 xff1a git init然后敲回车就有 xff
  • 深度揭秘阿里(蚂蚁金服)技术面试流程!附前期准备,学习方向

    上半年公司的项目很闲 xff0c 很多人觉得没意思陆续走了 xff0c 我考虑到自己的发展 xff0c 从6月底开始面 xff0c 面到7月底 xff0c 三十家公司 我从不打没准备的仗 xff0c 我是一个喜欢总结经验的人 xff0c 每
  • Git 中submodule的使用,终于有人说明白了

    背景 面对比较复杂的项目 xff0c 我们有可能会将代码根据功能拆解成不同的子模块 主项目对子模块有依赖关系 xff0c 却又并不关心子模块的内部开发流程细节 这种情况下 xff0c 通常不会把所有源码都放在同一个 Git 仓库中 有一种比
  • git 工具GitEye使用

    二 xff1a 签入 右键commit 可以选择需要签入的 xff0c 要加入注释才能签入 一 xff1a 比较
  • ROS笔记十(基于Python、Kinetic):rviz基础——快速配置并渲染点云和摄像机图像数据

    前言 xff1a rviz xff08 ROS visualization xff09 xff1a 用于机器人 传感器和算法的通用3D可视化系统 rviz能够绘制多种类型的数据流 特别是三维的数据 在ROS中所有类型的数据都被关联到一个参考
  • java面试必看书单

    编程之法 https legacy gitbook com book wizardforcel the art of programming by july details 白话经典算法之七大排序 链接 xff1a https pan ba
  • Java基础 - Integer和int的区别

    一 int和Integer的区别 两者的区别主要体现在以下几个方面 xff1a 1 数据类型不同 xff1a int 是基础数据类型 xff0c 而 Integer 是包装数据类型 xff1b 2 默认值不同 xff1a int 的默认值是
  • Lua + GraphicsMagick安装

    Lua 43 GraphicsMagick安装 图片的实时缩放功能是Nginx调用Lua脚本 xff0c Lua脚本在FastDFS中下载对应的图片保存到本地 xff0c 然后Lua调用GraphicsMagick实现图片的缩放功能 1 安
  • 零基础应该选择学习 C、C++、Java、python、web前端、C#、PHP、Linux选哪个编程语言好呢?

    众多的语言 xff0c 到底哪一门才是适合我呢 xff1f 小白 xff1a 大佬 xff0c 大佬 xff0c 编程语言也太多了 xff0c 到底我应该选择哪一种呢 xff1f 大佬 xff1a 首先呢 xff0c 我们先对常见的编程语言
  • 如何看英文技术文档

    https www jianshu com p af7d39cac6b8
  • 从工具的奴隶到工具的主人

    摘要 xff1a 我们每个人都是工具的奴隶 随着我们的学习 xff0c 我们不断的加深自己对工具的认识 xff0c 从而从它们里面解脱出来 现在我就来说一下我作为各种工具的奴隶 xff0c 以及逐渐摆脱它们的思想控制的历史吧 当我高中毕业进
  • 程序员,这四个学习建议值得收藏

    大家好 xff0c 我是本周的值班编辑 江南一点雨 xff0c 本周将由我为大家排版并送出技术干货 xff0c 大家可以在公众号后台回复 springboot xff0c 获取最新版 Spring Boot2 1 6 视频教程试看 在我看来
  • 底层原理解析

    目录 HashMap底层原理 xff1a ConcurrentHashMap 底层原理 HashMap底层原理 xff1a 1 HashMap概述 xff1a HashMap是一个散列桶 xff08 数组和链表 xff09 xff0c 它存