HashMap、HashTable、ConcurrentHashMap之间的区别及常见面试题

news2024/11/17 19:40:20
Java集合类有的集合类是存在线程安全的问题,但是由于之前对于集合类的使用都是在单线程的情况下使用的,不没有在多线程环境下使用,所以不涉及线程安全的问题;这篇博客着重讲解一下多线程环境下使用哈希表。

HashMap

HashMap本身不是线程安全的,所以在单线程的情况下可以放心使用,在多线程的情况下谨慎使用(可能会触发线程安全问题)。

HashTable

HashTap锁机制(HashTable如何实现加锁的)

HashTable相比于HashMap是线程安全的,可以在多线程的情况下使用;

1.源码分析

HashTable把哈希表中的关键方法(put,get等)进行了加锁操作:

通过源码可以看出,HashTable底层是通过synchronized对方法加了锁;

2.画图分析

这个图大致反映了底层如何对哈希表进行加锁的:对整个哈希表加了锁,此时只要是多个线程访问同一个HashTable对象时就会造成锁冲突!但是这种方法效率较为低,当多个线程访问不同链表上的数据时并不存在线程安全问题,此时加锁进行阻塞等待显得没有必要。

ConcurrentHashMap

Java1.8下的ConcurrentHashMap

Java1.8中,synchronized锁把每个链表的头结点作为锁对象,此时只有当多个线程访问并操作同一个链表下的数据时就会发生锁冲突,若访问的不是同一个链表下的数据时并不会发生锁冲突。

Java1.7和之前的ConcurrentHashMap

在Java1.7和之前,synchronized锁实现的是分段加锁,每三个链表加一次锁,本质上缩小了锁的范围,但是粒度切分的不够细,而且代码的实现较为繁琐。

ConcurrentHashMap相对于HashTable的优化

  1. ConcurrentHashMap相比于HashTable大大缩小了锁的冲突概率

ConcurrentHashMap把HashTable中的对整个哈希表加锁的操作拆分成了很多把小锁,HashTable中只要操作哈希表上的任意元素都会发生锁冲突,而ConcurrentHashMap只有多个线程操作同一个链表上的元素时才会存在线程安全问题(此时加锁控制线程安全),操作不同链表上的数据时并不会发生锁冲突(这也大大提高了效率),即只有多个对象针对同一个对象加锁时才会有锁竞争,才会有阻塞等待,针对不同对象,没有锁竞争!

  1. ConcurrentHashMap做了一个激进的操作,针对读操作不加锁,只针对写操作加锁

我们知道,在线程安全问题中:

读和读之间,没有冲突

写和写之间,有冲突

读和写之间,有冲突(因为存在脏读情况,可能会读到一个写了一半的结果

所以在ConcurrentHashMap中,用volatile关键字+原子的写操作来避免这种脏读情况,从而控制了线程安全。

  1. ConcurrentHashMap内部充分使用了CAS

CAS操作在CPU上一条原子性的指令,CAS避免使用锁而达到和锁一样控制线程安全的效果(只是CAS不会阻塞线程,多个线程对某个资源进行CAS操作时,只能有一个线程会操作成功,不成功的线程并不会被阻塞,只是会收到操作失败的信号),所以ConcurrentHashMap内部充分使用CAS就是为了在一定程度上减少锁的数目,从而减少开销来提高效率;另一方面size属性也可以通过CAS操作来进行更新,避免了重量级锁的情况。

  1. ConcurrentHashMap针对扩容,采取了“化整为零”的方式

HashMap/HashTable扩容:

创建一个更大的数组空间,把旧的数组上的链表上的每一个元素搬运到新的数组上,如果元素个数特别多的时,这样的搬运操作就会非常耗时;

ConcurrentHashMap扩容:

每次只会搬运一小部分的元素,旧的数组也会保留,每次put操作都往新数组上添加元素,同时进行一部分搬运(把一小部分旧的元素搬运到新数组上),每次get的时候,旧数组和新数组都会进行查询,每次remove的时候就把元素删除,经过一定的时间后,所有的元素都搬运好了,最后再释放旧数组。ConcurrentHashMap可以看成是在HashTable的基础上“化整为零”。

常见面试题

  1. ConcurrentHashMap的读是否要加锁,为什么?

答:读操作没有加锁. 目的是为了进一步降低锁冲突的概率. 为了保证读到刚修改的数据, 搭配了

volatile 关键字.

  1. 介绍下 ConcurrentHashMap的锁分段技术?

答:这个是 Java1.7 中采取的技术. Java1.8 中已经不再使用了. 简单的说就是把若干个哈希桶分成一个

"段" (Segment), 针对每个段分别加锁. 目的也是为了降低锁竞争的概率. 当两个线程访问的数据恰好在同一个段上的时候, 才触发锁竞争.

  1. ConcurrentHashMap在jdk1.8做了哪些优化?

答:取消了分段锁, 直接给每个哈希桶(每个链表)分配了一个锁(就是以每个链表的头结点对象作为锁对

象). 将原来 数组 + 链表 的实现方式改进成 数组 + 链表 / 红黑树 的方式. 当链表较长的时候(大于等于

8 个元素)就转换成红黑树.

  1. Hashtable和HashMap、ConcurrentHashMap 之间的区别?

答:HashMap: 线程不安全. key 允许为 null

Hashtable: 线程安全. 使用 synchronized 锁 Hashtable 对象, 效率较低. key 不允许为 null.

ConcurrentHashMap: 线程安全. 使用 synchronized 锁每个链表头结点, 锁冲突概率低, 充分利用

CAS 机制. 优化了扩容方式. key 不允许为 null

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

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

相关文章

一些开发时常用的网站或命令

目录关于gitgit下载网址git安装教程Gortoisegit下载地址关于PythonAnyWhere关于Linux压缩与解压命令关于python的相对与绝对路径使用_\_file_\_实现跨平台关于宝塔面板关于浏览器驱动下载本博客首次编辑于2023.01.04 ,后续将持续进行更新 关于git git下载网址 gi…

Linux - 系统文件目录说明

目录/ - 根目录/bin - 用户基础二进制文件目录/boot - 静态启动文件/dev - 设备文件/etc - 配置文件/home - 主目录/lib - 基础共享库/lib64 - 64位基础共享库/lostfound - 可恢复的文件/media - 可移动媒体/mnt - 临时挂载点目录/opt - 自选软件包/proc - 内核 & 进程文件…

【Node】事件循环机制

Node 中的异步 API 定时器:setTimeout、setIntervalI/O 操作:文件读写、数据库操作、网络请求…Node 独有的 API:process.nextTick、setImmediate 事件循环的流程 Node 的事件循环分为 6 个阶段,这 6 个阶段会按顺序反复运行运行…

高并发内存池项目

文章目录一、项目介绍二、什么是内存池2.1 池化技术2.2 内存池2.3 内存池的作用2.4 malloc三、设计定长内存池四、高并发内存池整体框架设计六、threadcache6.1 threadcache整体设计6.2 threadcache哈希桶映射对齐规则6.3 编写对齐和映射的相关函数6.4 编写ThreadCache类6.5 th…

电网头条知识竞赛题库答案(自动答题)

今天教你们自动完成2023年电网头条的知识竞赛,小编也为大家安排好了教程,首先呢需要知道电网助手,打开电网助手网页https://wwwl.lanzouw.com/b01w803yj 为了帮到大家,我特地分享出来,希望能给大家带来一丝丝便利&…

1.3第二周 星期二Samba、FTP

目录 01 Samba文件共享服务 Samba服务基础 2.主配置文件 02 linux文件传输服务 1.用户访问的Samba 03 FTP服务概述 1.vsftp知识预备 04 操作流程: 1.使用时记得装ftp的包:yum install ftp -y 2.装完之后启动服务&am…

【北京理工大学-Python 数据分析-2.1Matplotlib库入门】

Matplotlib库的使用 Matplotlib库由各种可视化类构成,内部结构复杂,受Matlab启发。matplotlib.pyplot是绘制各类可视化图形的命令字库,相当于快捷方式。 import matplotlib.pyplot as plt plt.plot([3,1,4,5,2]) plt.ylabel("Grade&qu…

实战四十七:基于机器(逻辑回归随机森林线性回归)学习预测销售门店的商品销量详细教程(代码+数据)

项目概述: 使用时间序列预测来预测来Corporacin Favorita 的数据的商店销售额。 具体来说,构建一个模型来更准确地预测在不同 Favorita 商店销售的数千种商品的单位销售额。您将使用包含日期、商店和商品信息、促销和单位销售的易于理解的训练数据集来练习您的机器学习技能。…

基于java ssm springboot+VUE疫情防疫系统系统前后端分离设计和实现

基于java ssm springbootVUE疫情防疫系统系统前后端分离设计和实现 博主介绍:5年java开发经验,专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留…

Goland中使用GoPlantUml生成ER关系图

前言 Golang语言在近些年的开发语言中异军突起,在越来越多的公司项目中频繁出镜,也有越来越多的中间件选择使用Golang语言进行实现。正所谓源码之下无秘密,更友好地翻读源码对于理解功能特性以及后续使用非常有帮助,观摩学习源码也…

RMAN异地恢复-适用于数据库量比较大的场景

之前验证异地备份,只对数据库做个全备就备份恢复了,这种适用于数据库比较小的场景,因为如果数据库量大的话,备份,拷贝备份,恢复数据库的时间就比较长,停业务的时间就会比较长。 如果数据库比较…

JavaWeb知识汇总

文章目录前导一、数据库1.相关概念2.数据模型3.SQL4.约束5.数据库设计6.多表查询7.事务二、JDBC1.步骤2.JDBC事务管理3.数据库连接池三、Maven1.maven生命周期2.maven坐标详解3.依赖管理四、Mybatis1.快速入门2.Mapper代理开发3.核心配置文件4.参数传递5.注解开发五、HTML1.快速…

【进阶C语言】字符串函数+内存函数

文章目录一.字符串函数1.strlen功能:求字符串长度(不包括\0)函数模拟实现:2.1 strcmp功能函数模拟实现2.2 strncmp3.1 strcat功能函数模拟实现3.2strncat4.1 strcpy功能函数模拟实现4.2 strncpy5.strstr功能函数模拟实现6.strtok功…

论文《An Effective Consistency Constraint for Sequential Recommendation》

C2Rec: An Effective Consistency Constraint for SequentialRecommendation 这篇文章提出了序列推荐建模中一种有效的一致性约束防范,不用修改模型结构,仅仅添加2个额外的损失函数,就能达到非常好的效果。不像基于对比学习的方法&#xff0…

C++初阶--string

目录 string对象的创建: 遍历修改 const修饰的迭代器(只读): 反向迭代器: reserve与resize: find,rfind,substr: insert: erase: getchar、getline: string对…

Java基础学习笔记(十一)—— 包装类与泛型

包装类与泛型1 包装类1.1 基本类型包装类1.2 Integer类1.3 自动装箱 / 拆箱2 泛型2.1 泛型概述2.2 泛型的用法2.3 类型通配符1 包装类 1.1 基本类型包装类 基本类型包装类的作用 将基本数据类型封装成对象 的好处在于可以在对象中定义更多的功能方法操作该数据 public stat…

✿✿✿JavaScript --- Ajax异步请求与JSONP 跨域请求

目 录 一、原生的Ajax请求 1.异步和同步 2.Ajax介绍 3.实现方式 (1)原生的JS实现方式(了解) (2)原生AJax发送Post请求,并携带请求参数 二、JQuery封装后的Ajax 1.JQeury实现方式 2. $.get():发送get请求 3.$.post()&…

存储随笔2022年度最受欢迎文章榜单TOP15

回首2022感谢各位粉丝朋友的一路支持与陪伴存储随笔为您献上2022年度最受欢迎文章榜单TOP152023,一起向未来!TOP1:固态硬盘SSD入门级白皮书主要从固态硬盘的原理/接口形态/寿命/使用场景/等不同角度,来对比不同的人群需要什么样的…

[linux]vim编辑器

📟作者主页:慢热的陕西人 🌴专栏链接:Linux 📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言 本博客主要讲解vim的使用和一些vim的常用操作,以及如何解决…

Flow 转 LiveData 后数据丢了,肿么回事?

翻译自: https://arkadiuszchmura.com/posts/be-careful-when-converting-flow-to-livedata/ 前言 最近我在负责一段代码库,需要在使用 Flow 的 Data 层和仍然依赖 LiveData 暴露 State 数据的 UI 层之间实现桥接。好在 androidx.lifecycle 框架已经提供…