ConcurrentHashMap 的优化及其与HashTable, HashMap的区别

news2024/12/23 0:18:50

目录

1.优化一:减小锁粒度

2.优化二:只针对写操作加锁

3.优化三:CAS

4.优化四:扩容方式


HashMap是线程不安全的,HashTable是线程安全的,关键方法加锁了.我们更推荐的是ConcurrentHashMap ,更优化的线程安全哈希表

接下来我们总结一下ConcurrentHashMap 进行了哪些优化,比HashTable好在哪里

1.优化一:减小锁粒度

最关键的优化:ConcurrentHashMap 相比于HashTable大大缩小了所冲突的概率,将一把大锁转换成多把小锁了

Hash Table做法是直接在方法上加synchronized,相当于给this加锁,只要操作哈希表上的任意元素,都会产生加锁,也就都可能发生锁冲突!  

实际上不难发现,基于哈希表的结构特点,有些元素并发操作的时候,是不会产生线程安全问题的,也不需要锁控制!我们看看哈希表的结构

如果此时,元素12在同一个链表上,线程A修改元素1,线程B修改元素2,是否有线程安全问题呢??

修改(包括增删改),很明显是会有线程安全问题的,如果元素相邻,并发的删除/插入时,就需要修改两个节点的next的指向,这个情况是需要加锁的!再来看这种情况:

如果元素3和元素4 没有在相同的链表上,此时多线程并发操作34就不会有线程安全问题 ,也就相当于多个线程并发修改不同的变量,是没有线程安全问题的,也就不需要加锁

但是哈希表时直接加了个大锁

无论是12还是34这种情况,都是直接加锁,串行化了,那么就大大提高了锁冲突的概率,任何两个元素都会有锁冲突,即使是不在同一个链表上的,这也是不用哈希表的最主要原因!!

那么ConcurrentHashMap又是如何优化的呢?

ConcurrentHashMap的做法是:每个链表都有各自的锁,而不是整个哈希表只用一把锁了,具体来说,就是使用每个链表的头节点,作为锁对象.

两个线程针对同一个锁对象加锁才会产生锁竞争,才发生阻塞等待,针对不同的锁对象时不会有锁冲突的,所以就从哈希表的两个任意元素之间都有锁冲突转化为了只有同一链表上的任意元素之间才有锁冲突!!

此时是把锁的粒度变小了,针对12情况,是同一个链表上的元素,是针对相同的锁对象进行加锁,会有锁竞争,会保证线程安全.针对34情况,是针对不同的锁对象进行加锁,不会有锁竞争,没有阻塞等待,程序运行也会更快.

 上述情况是jdk1.8及其以后的情况,1.7之前ConcurrentHashMap采用的是"分段锁"大概意思是让几个链表使用同一把锁.

分段锁,本质上也是缩小锁的范围,从而降低锁冲突的概率,但是这种做法不够合理,粒度切分的不够细,代码实现也更繁琐.

2.优化二:只针对写操作加锁

ConcurrentHashMap做了一个激进的优化操作,针对读操作,不加锁,只针对写操作加锁!

读和读之间没有冲突,写和写之间有冲突,读和写之间也没有冲突...其实很多场景下,读写之间不加锁控制,可能会读到写了一半的数据,相当于脏读了.写操作不是原子的(ConcurrentHashMap使用了volatile+原子的写操作维护线程安全)

3.优化三:CAS

ConcurrentHashMap内部充分使用了CAS,通过这个进一步的削减加锁操作的数目,比如维护元素个数..

4.优化四:扩容方式

针对扩容采取了"化整为零"的方式

Hash Map/HashTable扩容:

是创建一个更大的数组空间,把旧的数组上的链表上的每个元素搬运到新的数组上(删除加插入)

这个扩容操作会在某次put(插入后超过负载因子了)后触发,如果元素个数特别多,那么就会导致搬运操作太多,比较耗时,就会出现某次put比平常put卡很多倍,时间是用来搬运了

ConcurrentHashMap中的扩容是采取每次搬运一小部分元素.创建新的数组,旧数组也保留,每次put操作,都往新的数组添加,同时进行一部分搬运,把一小部分旧的元素搬运到新的数组上.

每次get的时候旧数组和新数组都查询,每次remove的时候,只是把元素删了就行,经过一段时间,所有的数据都搬运好了,最终再释放旧数组

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

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

相关文章

Nessus 扫描log4J漏洞

系列文章 Nessus介绍与安装 Nessus Host Discovery Nessus 高级扫描 Nessus 扫描web服务 Nessus 扫描log4J漏洞 1.扫描环境搭建 1.centos7 安装装宝塔面板 2.面板里下载docker 3.进入centos检查docker是否生效 docker --version4.安装docker-compose Docker Compose是一个…

使用WordPress搭建知识库门户网站的优缺点

使用知识库软件进行知识管理,帮助企业节约成本,为客户提供一个自助服务平台,提高客户满意度,据调查,73%的客户宁愿在网上搜索答案,而不是给工作人员打电话或者发短信,搭建一个知识库可能会耗费时…

TCP如何保证可靠传输,为什么应用层还需要确认机制

TCP的可靠传输实现 以下区别: 1、可靠传输(有序,保证对方一定接受到) 2、流量控制 这两个功能都是依靠滑动窗口来实现的 TCP实现可靠传输依靠的有 序列号、自动重传、滑动窗口、确认应答等机制。 序列号 首先我们说下序列号&am…

文件操作相关知识

1、为什么使用文件 前面我们在实现通讯录时,每次运行结束后,我们所存储的数据都会消失。这是因为我们将数据存储在栈区、堆区等内存上,而内存是不具有持久性的,程序退出时,权限还给操作系统,这些数据就会丢…

Unity 3D PC平台发布|| Unity 3D Web 平台发布||Unity 3D Android平台发布

Unity 3D PC平台发布 PC 是最常见的游戏运行平台。 随着欧美游戏的崛起,PC 平台随之发生游戏登陆大潮。 在 PC 平台上发布游戏的步骤: 打开要发布的 Unity 3D 工程,执行 File → Build Settings 菜单命令。在 Platform 列表框中选择 PC&am…

Jenkins, docker-compose动态修改镜像版本升级部署

docker-compose镜像版本动态控制 提取.env文件进行配置通用环境变量 # 当前机器用户的home路径 HOST_HOME/home/guimu # 上传文件临时路径 TMP_DATA_PATH${HOST_HOME}/tempdata/ # media的home路径 MEDIA_HOME/media # 挂载的mysql的data路径 MYSQL_DATA_PATH${HOST_HOME}/my…

go 函数或者方法参数调用的过程

前言 最近做项目,使用go开发,但是在发生函数调用传参数时,对指针的指针的传递有难以理解的代码,就此分析过程。尤其是对于多重指针作为参数,而且对于一些内置函数的修改逻辑也需深入的理解。 1. demo package slice…

client-go源码学习(四):自定义Controller的工作原理、WorkQueue

本文基于Kubernetes v1.22.4版本进行源码学习,对应的client-go版本为v0.22.4 4、自定义Controller的工作原理 Controller中主要使用到Informer和WorkQueue两个核心组件 Controller可以有一个或多个Informer来跟踪某一个resource。Informer跟Kubernetes API Server保…

安装 Visual Studio Code、MinGW-w64、CMake

文章目录1.安装 Visual Studio Code1.1 下载1.2 安装2.安装 MinGW-w642.1 下载2.2 解压到合适的目录下2.3 添加到环境变量2.4 测试是否安装成功3.安装 CMake3.1 下载3.2 解压到合适的目录下3.3 添加到环境变量3.4 测试是否安装成功1.安装 Visual Studio Code 1.1 下载 Visual…

Options API

computed计算属性 1、复杂data的处理方式 我们知道,在模板中可以直接通过插值语法显示一些data中的数据。 但是在某些情况,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示; 比如我们需要对多个d…

自动驾驶控制算法之车辆纵向控制(project)

本文为深蓝学院-自动驾驶控制与规划-第二章作业 目录 1 project introduction 2 思路提示 3 解决积分饱和的方法 3.1 IC 积分遇限削弱法 3.2 BC 反馈抑制抗饱和 4 ROSLGSVL联合仿真 1 project introduction 本项目希望大家根据PID控制方法实现一个巡航控制系统。我们已…

深度学习之边缘检测算法论文解读(EDTER: Edge Detection with Transformer)

引言 边缘检测是计算机视觉中最基本的问题之一,具有广泛的应用,例如图像分割[8,23,39,44,45,47]、对象检测[23]和视频对象分割[5,57,59]。给定输入图像,边缘…

webpack-dev-server:静态资源目录配置

目录 webpack-dev-server Webpack项目-配置自动打包 访问错误信息分析 简单配置静态资源访问目录 完整配置静态资源访问目录 directory属性 staticOptions属性 publicPath属性 serveIndex属性 watch属性 完整配置webpack.config.js示例 默认显示index.html内容配置 默…

fsdb DUMP的操作记录

参考链接: https://blog.csdn.net/ohuo666/article/details/124973939https://blog.csdn.net/ohuo666/article/details/124973939 https://blog.csdn.net/yuexiangallan/article/details/121760768https://blog.csdn.net/yuexiangallan/article/details/121760768…

基于 DolphinDB 的行情中心解决方案

随着国内量化金融的高速发展,行情数据所包含的微观交易结构信息越来越受到券商自营团队、资管团队以及各类基金的重视。这些交易团队迫切希望拥有一个与生产环境类似的投研仿真环境,提升研发的效率和质量。作为国内领先的高性能时序数据库厂商&#xff0…

【地铁上的Redis与C#】数据类型(七)--List类型

我们这篇文章开始讲解list类型。 什么是list list是一个存储空间保存多个数据,底层使用双向链表存储结构实现的一种Redis数据类型,。list类型一般用在存储多个数据,并需要对数据进入存储空间的顺序进行区分的情况下。list的存储方式是一个存…

气泡法检漏技术特点分析和新型压力衰减法测试技术

摘要:针对传统的气泡法检漏技术,本文详细介绍了气泡法的基本原理、气泡法中的两种标准方法——加压法和真空法以及对应的标准规范,并对这两种气泡法进行了对比分析。本文还对气泡法的技术特点进行了分析,指出了气泡法检漏技术的局…

使用ruoyi-vue控制数据权限

说在前面 啥是数据权限?例如校长可以看到全部学生的信息,系主任可以看到该院系的学生信息,老师可以看到本班的学生信息,学生自己只能查看自己的信息 对于ruoyi的角色,我们只能控制用户可以访问那些菜单以及接口,而不能控制接口返回的数据 假如有这样一个需求,不同用户上传各…

赛狐ERP | 亚马逊卖家FBA常见问题解析!

许多亚马逊卖家在使用亚马逊FBA时经常会遇到一些问题,如FBA如何收费、如何提升发货数量、物流方式问题等问题,这些问题是常见问题,也是亚马逊卖方们应该把握的问题。下面就来跟大家分享一些常见的亚马逊FBA相关问题。一、亚马逊FBA如何收费&a…

OSCP_vulnhub—GOLDENEYE: 1

vulnhub—GOLDENEYE: 1About信息搜集查看js泄露POP3 密码破解及登录使用admin/xWinter1995x!登录 getshell提权About GoldenEye: 1 ~ VulnHub Download (Mirror): https://download.vulnhub.com/goldeneye/GoldenEye-v1.ova DHCP service: Enabled IP address: Automaticall…