ConcurrentHashMap底层原理?

本文为面试必备系列篇,不深入叙述,具体细节可自行查询。

可能会问的问题

1、用过ConcurrentHashMap吗?
2、为什么要用ConcurrentHashMap
3、HashMapHashTable的区别,引出ConcurrentHashMap
4、HashMap在多线程环境下存在线程安全问题,那你一般都是怎么处理这种情况的?
5、能说一下ConcurrentHashMap是怎么实现的吗?

为什么要用ConcurrentHashMap?

在并发编程中使用HashMap可能会导致程序陷入死循环,而使用线程安全的HashTable效率又非常低,所以采用了ConcurrentHashMap

单看这个回答,就会牵扯到「为和编发编程中使用HashMap会导致程序陷入死循环?」和「HashTable为何效率低下?」这两个问题,具体可参考上篇 > 面试必备:HashMap底层数据结构?jdk1.8算法优化,hash冲突,扩容等问题

关于ConcurrentHashMap实现原理的两个参考回答,自己可以重新组织一下:

ConcurrentHashMap采用的是分段式锁,与之对应的就是HashTableHashTable使用的是Synchronize关键字,是对一个大的数组加一把锁,其实是对对象加锁,锁住的是对象整体,性能肯定是比较差的,现在ConcurrentHashMap是将大数组拆分成许多的小数组,每一个小数组拥有一把锁,允许多个修改操作并发进行。

ConcurrentHashMap采用的是分段式锁,可以理解为把一个大的Map拆封成N个小的Segment,在put数据时会根据hash来确定具体存放在哪个Segment中,Segment内部的同步机制是基于Lock操作的,每一个Segment都会分配一把锁,当线程占用锁访问其中一段数据时,其他段的数据也能被其他线程访问,也就是实现并发访问。

继续拓展,分段式锁是如何实现的?

ConcurrentHashMapJDK1.7JDK1.8之间是有区别的,当然,这个问题也可以这样问:

能说一下ConcurrentHashMap在JDK1.7和JDK1.8中的区别吗?

1、JDK1.7:

HashEntry数组 + Segment数组 + Unsafe 「大量方法运用」

JDK1.7中数据结构是由一个Segment数组和多个HashEntry数组组成的,每一个Segment元素中存储的是HashEntry数组+链表,而且每个Segment均继承自可重入锁ReentrantLock,也就带有了锁的功能,当线程执行put的时候,只锁住对应的那个Segment 对象,对其他的 Segmentget put 互不干扰,这样子就提升了效率,做到了线程安全。

额外补充:我们对 ConcurrentHashMap 最关心的地方莫过于如何解决 HashMapput 时候扩容引起的不安全问题?

JDK1.7ConcurrentHashMapput 方法中进行了两次 hash 计算去定位数据的存储位置,尽可能的减小哈希冲突的可能行,然后再根据 hash 值以 Unsafe 调用方式,直接获取相应的 Segment,最终将数据添加到容器中是由 segment对象的 put 方法来完成。由于 Segment 对象本身就是一把锁,所以在新增数据的时候,相应的 Segment对象块是被锁住的,其他线程并不能操作这个 Segment 对象,这样就保证了数据的安全性,在扩容时也是这样的,在 JDK1.7 中的 ConcurrentHashMap扩容只是针对 Segment 对象中的 HashEntry 数组进行扩容,还是因为 Segment 对象是一把锁,所以在 rehash 的过程中,其他线程无法对 segmenthash 表做操作,这就解决了 HashMapput 数据引起的闭环问题。

2、JDK1.8:

JDK1.7:ReentrantLock+Segment+HashEntry
JDK1.8:Synchronized+CAS+Node+红黑树

JDK1.8屏蔽了JDK1.7中的Segment概念呢,而是直接使用「Node数组+链表+红黑树」的数据结构来实现,并发控制采用 「Synchronized + CAS机制」来确保安全性,为了兼容旧版本保留了Segment的定义,虽然没有任何结构上的作用。

总之JDK1.8中优化了两个部分:

放弃了 HashEntry 结构而是采用了跟 HashMap 结构非常相似的 Node数组 + 链表(链表长度大于8时转成红黑树)的形式

Synchronize替代了ReentrantLock,我们一直固有的思想可能觉得,Synchronize是重量级锁,效率比较低,但为什么要替换掉ReentrantLock呢?

1、随着JDK版本的迭代,本着对Synchronize不放弃的态度,内置的Synchronize变的越来越“轻”了,某些场合比使用API更加灵活。

2、加锁力度的不同,在JDK1.7中加锁的力度是基于Segment的,包含多个HashEntry,而JDK1.8锁的粒度就是HashEntry(首节点),也就是1.8中加锁力度更低了,在粗粒度加锁中 ReentrantLock 可能通过 Condition 来控制各个低粒度的边界,更加的灵活,而在低粒度中,Condition的优势就没有了,所以使用内置的 Synchronize 并不比ReentrantLock效果差。

18年专科毕业后,期间一度迷茫,最近我创建了一个公众号用来记录自己的成长。

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

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

相关文章

[js] js操作节点的方法有哪些?

[js] js操作节点的方法有哪些? 创建节点createElement() 创建一个元素节点createTextNode() 创建一个文本节点createAttribute() 创建一个属性节点createComment() 创建一个注释节点插入节点appendChild() 把节点插入到父节点的末尾insertBefore() 把节点插入到父节…

【刷题】洛谷 P2709 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数。他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数。小B请你帮助他回答询问。 输入输出格式 输入格式&…

支付宝支付-当面付之扫码支付「扫码支付」

前言 支付宝支付—沙箱环境使用支付宝支付-支付宝PC端扫码支付支付宝支付-手机浏览器H5支付支付宝支付-当面付之扫码支付「本文」 当面付包含两种支付方式:商品条形码支付 扫码支付 经过前面两篇PC端扫码支付、手机H5支付,我们可以看到一个共同的特点就…

[js] 写一个格式化时间的方法

[js] 写一个格式化时间的方法 function dateToString(date, format yyyy-MM-dd) {const d new Date(date);let result format;const _config {y: d.getFullYear(),M: d.getMonth() 1, // 月d: d.getDate(), // 日h: d.getHours(), // 小时m: d.getMinutes(), // 分s: d.g…

01: awk常用

1.1 awk基本使用 1、找出当前登录用户数量 [rootlocalhost ~]# w14:09:07 up 48 min, 2 users, load average: 0.00, 0.01, 0.06 USER TTY FROM LOGIN IDLE JCPU PCPU WHAT root :0 :0 204月18 ?xdm? 59.24s 0.04s g…

MybatisCodeHelperNew-2.8.1-191-201插件使用

本文测试环境IDEA_2020.1,文中提供了MacOS用户操作截图 1、文件解压后放置plugs插件目录「Windows」 扫码回复「139」 下载后将文件解压,将压缩包内的 MyBatisCodeHelper-Pro 放入 IDEA 安装目录的 plugins 目录。 2、如果你是MacOS用户「MacOS」 同样找…

[js] pjax和ajax的区别是什么?

[js] pjax和ajax的区别是什么? pjax 是一个 jQuery 插件,它通过 ajax 和 pushState 技术提供了极速的(无刷新 ajax 加载)浏览体验,并且保持了真实的地址、网页标题,浏览器的后退(前进&#xff…

Redis简单案例(四) Session的管理

Redis简单案例(四) Session的管理 原文:Redis简单案例(四) Session的管理负载均衡,这应该是一个永恒的话题,也是一个十分重要的话题。毕竟当网站成长到一定程度,访问量自然也是会跟着增长,这个时候, 一般都会对其进行负…

MacOS中Elasticsearch的安装「借助Homebrew」

1、Homebrew 如果你已经安装过Homebrew了,那么你可以跳过这一步,直接进行Elasticsearch安装步骤; Homebrew是一款MacOS平台下的软件包管理工具,拥有安装、卸载、更新、查看、搜索等很多实用的功能,强烈推荐安装。 请…

[js] 微信小程序实现轨迹回放,微信原生小程序,基于uniapp的小程序?

[js] 微信小程序实现轨迹回放,微信原生小程序,基于uniapp的小程序? 需要写出轨迹拖动,进度条,开始,暂停,结束功能。 个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易…

负载均衡中使用 Redis 实现共享 Session

最近在研究Web架构方面的知识,包括数据库读写分离,Redis缓存和队列,集群,以及负载均衡(LVS),今天就来先学习下我在负载均衡中遇到的问题,那就是session共享的问题。 一、负载均衡 负…

Typora中使用Gitee图床

1、前言 之前好友写了一篇「使用gitee作为图床 ,写markdown自动上传文件」,初衷是由于我一直使用的是Typora来写博客「力推」,但之前的版本都不支持图床功能,现在新版本已经有了图床功能了,赶紧入坑。 本篇环境:MacOS…

[js] 异步请求重试策略有哪些呢?

[js] 异步请求重试策略有哪些呢? 重试次数、重试时间间隔等个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易, 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

【NOIP2017模拟6.25】小W的动漫

题目 小W最近迷上了日本动漫,每天都有无数部动漫的更新等着他去看,所以他必须将所有的动漫排个顺序,当然,虽然有无数部动漫,但除了1号动漫,每部动漫都有且仅有一部动漫是它的前传(父亲&#xff…

用Elasticsearch代替数据库存储日志方式

之前的项目中一直使用的是数据库表记录用户操作日志的,但随着时间的推移,数据库log单表是越来越大「不考虑删除」,再加上近期项目中需要用到Elasticsearch,所以干脆把这些用户日志迁移到ES上来了。 环境:SpringBoot2.2…

[js] 写一个方法实现promise失败后自动重试

[js] 写一个方法实现promise失败后自动重试 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv&…

jacky解读麻省理工《计算机科学与Python编程导论》第1集

文&#xff1a;数据分析&#xff0d;jacky(朱元禄) &#xff08;一&#xff09;导言 本课程讲的中心思想就是五个字&#xff1a;计算机思维Python只是辅助工具&#xff0c;是辅助大家理解计算机思维&#xff0c;仅此而已 急功近利是人性&#xff0c;适得其反是结果&#xff1a;…

如何理解Java中的自动拆箱和自动装箱?

小伟刚毕业时面的第一家公司就被面试官给问住了&#xff0c;记忆尤深啊… 如何理解Java中的自动拆箱和自动装箱&#xff1f; 自动拆箱&#xff1f;自动装箱&#xff1f;什么鬼&#xff0c;听都没听过啊&#xff0c;这…这…知识盲区… 回到家后小伟赶紧查资料&#xff0c;我…

[js] 实现多张图片合成一张的效果

[js] 实现多张图片合成一张的效果 原理是使用canvas画布。在页面加载前 mounted方法里&#xff1a;setTimeout(() > {this.changeimg();}, 1000);changeimg( )方法&#xff1a;changeimg(){var self this;var imgsrcArray [require(../../assets/image/income/background…

chrome浏览器中解决embed标签 loop=true 背景音乐无法循环的问题。

今天试了下在html网页中加入背景音乐并设置为循环播放。一开始用<embed>标签&#xff0c;设置loop"true", 但是结果发现在IE浏览器可以&#xff0c;但是在chrome浏览器却无法实现循环&#xff0c; 播放完一次自动停止了。代码如下&#xff1a; <embed src&q…