HashMap线程不安全|Hashtable|ConcurrentHashMap
文章目录
- 常见集合线程安全性
- HashMap为什么线程不安全?
- 怎么保证HashMap线程安全
- Hashtable
- ConcurrentHashMap 引入细粒度锁
- 代码中分析
- 总结
- 小结
常见集合线程安全性
ArrayList、LinkedList、TreeSet、HashSet、HashMap、TreeMap等都是线程不安全的。
HashTable是线程安全的。
HashMap为什么线程不安全?
来看个例子
public static void main(String[] args) {HashMap<String, Integer> map = new HashMap<>();// 创建两个线程同时向HashMap中添加1000个元素Thread thread1 = new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 1000; i++) {map.put(String.valueOf(i), i);}}});Thread thread2 = new Thread(new Runnable() {@Overridepublic void run() {for (int i = 1000; i < 2000; i++) {map.put(String.valueOf(i), i);}}});// 启动线程thread1.start();thread2.start();try {// 等待两个线程执行完成thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}// 输出 HashMap 的大小System.out.println("map集合大小: " + map.size());}//输出结果:map集合大小:1920(这个数字在变动)
在多线程环境下,如果多个线程同时对 HashMap 进行修改操作(例如添加、删除元素),可能会导致数据结构破坏,进而引发各种问题,比如丢失数据等。
怎么保证HashMap线程安全
第一:
如何保证HashMap的线程安全呢?可能你们想到了synchronized ,确实,你可以通过在添加元素时使用 synchronized 来确保 HashMap 的线程安全性。这样做可以在多线程环境下保证对 HashMap 的操作是互斥的,从而避免了多个线程同时修改 HashMap 导致的线程不安全问题。
Thread thread1 = new Thread(new Runnable() {@Overridepublic void run() {//synchronized (map) 中的 map 是一个对象锁//它指定了在执行同步代码块时使用的锁对象synchronized (map) {for (int i = 0; i < 1000; i++) {map.put(String.valueOf(i), i);}}}});
当一个线程进入同步代码块(即 synchronized (map) 所包围的部分)时,它会尝试获取 map 对象的锁。如果这个锁当前没有被其他线程占用,那么该线程将获得锁,并可以执行同步代码块中的操作;如果该锁已经被其他线程占用,那么该线程将被阻塞,直到锁被释放。被锁住的对象将会在同步代码块执行完毕后自动释放。
第二:
使用Collections.synchronizedMap() 包装:
Map<Integer, String> synchronizedMap = Collections.synchronizedMap(new HashMap<>());
这样可以获得一个线程安全的 HashMap,但性能可能不如 ConcurrentHashMap。
第三:
使用 ConcurrentHashMap:
ConcurrentHashMap 是专门为高并发环境设计的,JDK 1.8它使用了 CAS + synchronized 来保证线程安全性,而且性能表现优秀。
Map<Integer, String> concurrentHashMap = new ConcurrentHashMap<>();
Hashtable
Hashtable 使用的是全表加锁的方式来保证线程安全,也就是说,当一个线程要对 Hashtable 进行读写操作时,它会对整个 Hashtable 加锁,阻塞其他所有线程的访问

HashTable 替代品 ConcurrentHashMap ,ConcurrentHashMap 引入了细粒度锁和无锁读取等技术,大大提高了并发环境下的性能和扩展性
ConcurrentHashMap 引入细粒度锁
ConcurrentHashMap 之所以是线程安全的,主要是因为它在内部实现时采用了特殊的机制来确保多个线程同时访问和修改数据时不会发生冲突。
JDK 1.7 版本中的实现:
ConcurrentHashMap 在 JDK 1.7 中使用了分段锁(Segmentation)的结构,将整个哈希表分成了多个段(Segment),每个段有自己的锁。不同段之间的修改操作可以并发进行(提高了并发性能),只有在同一段内的操作才需要竞争锁。
JDK 1.8 版本中的优化:
JDK 1.8 对 ConcurrentHashMap 进行了重大优化,废弃了分段锁的设计,而是采用了更细粒度的锁分离技术。
在 JDK 1.8 中,ConcurrentHashMap 内部使用了基于 CAS(Compare and Swap 是一种原子操作,用于在多线程环境下实现对共享数据的安全更新。CAS 是一种乐观锁机制,可以避免使用传统的互斥锁,提高了并发性能。) 操作的 synchronized 关键字
同时,ConcurrentHashMap 在 JDK 1.8 中引入了红黑树作为链表的替代结构,当链表长度达到一定阈值时,会将链表转换为红黑树,以提高查找效率。这种优化又提高了 ConcurrentHashMap 的并发性能和吞吐量。
代码中分析
来看看put方法
public static void main(String[] args) {ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();map.put("a",111);}
在 JDK8 中,ConcurrentHashMap 的实现方式已经改变,不再采用分段锁的方式,而是采用了 CAS+Synchronized 的方式来保证线程安全
我们需要先了解tabAt ,casTabAt(本质是CAS 算法,看下面源码可知)的利用来保障线程安全的操作:
tabAt 方法用于从哈希表数组 tab 中获取指定索引 i 处的节点数组。
casTabAt 方法用于原子性地将哈希表数组 tab 中指定索引 i 处的值从 c 更新为 v。(CAS 比较并交换,可实现原子操作)
put源码分析:
-
遍历桶(Bin)时不加锁:
首先,代码会根据hash值找到对应的桶(tab[i]),并且如果该桶是空的(f == null),会尝试通过CAS(compare-and-swap)操作将新的节点放入其中,这一部分操作是无锁的。else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null)))break; } -
对非空桶的头节点加锁:
当桶tab[i]已经存在节点时,会进入synchronized (f)代码块,其中f是桶中的头节点。通过对头节点f加锁,保证对该桶中的修改是线程安全的。synchronized (f) {if (tabAt(tab, i) == f) {// 锁定成功后,进行进一步操作} }- 这种加锁方式是“桶级别”的锁,而不是对整个
HashMap或ConcurrentHashMap加全局锁,因此不会影响其他线程对其他桶的访问。
- 这种加锁方式是“桶级别”的锁,而不是对整个

-
对链表或树结构的操作:
加锁后,代码会对链表中的节点进行遍历,或者在红黑树中进行查找(如果桶已经转化为树形结构)。在这个过程中,同步块只对桶的头节点加锁,而不是对每个节点加锁。因此,在修改链表或树的过程中,保证了线程安全性,但并不会影响其他线程对其他桶的操作。-
如果该桶是链表结构,会遍历链表并进行元素的插入操作:
for (Node<K,V> e = f;; ++binCount) {K ek;if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) {oldVal = e.val;if (!onlyIfAbsent)e.val = value;break;}Node<K,V> pred = e;if ((e = e.next) == null) {pred.next = new Node<K,V>(hash, key, value, null);break;} } -
如果该桶是树形结构(红黑树),则调用
putTreeVal方法进行树中的插入操作:if (f instanceof TreeBin) {Node<K,V> p;binCount = 2;if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) {oldVal = p.val;if (!onlyIfAbsent)p.val = value;} }
-
-
加锁粒度:
由于只对每个桶的头节点加锁,因此即使多个线程同时对不同的桶进行操作,也不会相互阻塞。只有在同一个桶中有多个线程试图修改数据时,才会发生锁竞争。这种设计提高了并发性能,相比全局锁的方式有更高的并发吞吐量。 -
树化操作:
当链表中的节点数量超过TREEIFY_THRESHOLD时,会将链表转化为红黑树以提高查询和修改效率。树化也是在线程安全的环境下进行的,但依然是通过对头节点加锁实现的。if (binCount >= TREEIFY_THRESHOLD)treeifyBin(tab, i);
总结
- 加锁机制:对每个桶(
tab[i])的头节点进行加锁。这种锁定策略使得同一个桶中的修改是线程安全的。 - 并发性能优化:这种设计避免了全局锁,提高了在高并发环境下的性能。当多个线程操作不同的桶时,操作不会相互干扰。
小结
而在 JDK 1.8 中,ConcurrentHashMap 放弃了分段锁,而是采用了更为精细的桶结构。每个桶可以独立加锁,使得并发修改操作可以更细粒度地进行。此外,当桶中的元素数量达到一定阈值时,链表结构会转变为红黑树,以减少搜索时间。这种锁分离技术提高了并发性能,使得 ConcurrentHashMap 在并发情况下表现更加出色。它是通过 CAS + synchronized 来实现线程安全的,并且它的锁粒度更小,查询性能也更高。
❤觉得有用的可以留个关注ya❤
相关文章:
HashMap线程不安全|Hashtable|ConcurrentHashMap
文章目录 常见集合线程安全性HashMap为什么线程不安全?怎么保证HashMap线程安全 HashtableConcurrentHashMap 引入细粒度锁代码中分析总结 小结 常见集合线程安全性 ArrayList、LinkedList、TreeSet、HashSet、HashMap、TreeMap等都是线程不安全的。 HashTable是线…...
01 会计概述
会计的定义:会计是以货币为计量单位,反映和监督一个单位经济活动的一种经济管理活动。会计的作用:就是提供决策信息、促使企业加强经营管理、考核管理层经济责任履行情况。会计人员职业道德:坚持诚信,守法奉公…...
开放式激光振镜运动控制器在Ubuntu+Qt下的文本标刻
开放式激光振镜运动控制器在UbuntuQt下的文本标刻 上节课程我们讲述了如何通过UbuntuQt进行振镜校正(详情点击→开放式激光振镜运动控制器在UbuntuQt下的激光振镜校正),本节文本标刻是在振镜校正的前提下实现的。 在正式学习之前࿰…...
推荐3款AIai论文大纲一键生成文献,精选整理!
在当前的学术写作环境中,AI论文大纲生成工具已经成为许多学者和学生的重要助手。这些工具不仅能够快速生成高质量的论文大纲,还能提供内容填充、文献引用和查重修改等全方位的服务。以下是三款值得推荐的AI论文大纲一键生成文献工具:千笔-AIP…...
数据库之索引<保姆级文章>
目录: 一. 什么是索引 二. 索引应该选择哪种数据结构 三. MySQL中的页 四. 索引分类及使用 一. 什么是索引: 1. MySQL的索引是⼀种数据结构,它可以帮助数据库高效地查询、更新数据表中的数据。 索引通过 ⼀定的规则排列数据表中的记录&#x…...
多维时序 | Matlab基于BO-LSSVM贝叶斯优化最小二乘支持向量机数据多变量时间序列预测
多维时序 | Matlab基于BO-LSSVM贝叶斯优化最小二乘支持向量机数据多变量时间序列预测 目录 多维时序 | Matlab基于BO-LSSVM贝叶斯优化最小二乘支持向量机数据多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab基于BO-LSSVM贝叶斯优化最小二乘支…...
Netty笔记03-组件Channel
文章目录 Channel概述Channel 的概念Channel 的主要功能Channel 的生命周期Channel 的状态Channel 的类型channel 的主要方法 ChannelFutureCloseFuture💡 netty异步提升的是什么要点总结 Channel概述 Channel 的概念 在 Netty 中,Channel 是一个非常重…...
1----安卓机型修复串码 开启端口 檫除基带 支持高通与MTK机型工具预览与操作解析
在玩机过程中。很多玩家会碰到各种各样的故障 。其中最多的就在于基带 串码类。由于目前的安卓机型必须修改或者写入串码等参数必须开启端口。而一些初级玩友不太了解开启参数端口的步骤。这个工具很简单的为安卓机型开启端口。并且操作相对简单。 此工具基本功能 1-----可以…...
Docker容器技术1——docker基本操作
Docker容器技术 随着云计算和微服务架构的普及,容器技术成为了软件开发、测试和部署过程中的重要组成部分。其中,Docker作为容器技术的代表之一,以其简便易用的特点赢得了广大开发者的青睐。 Docker允许开发者在轻量级、可移植的容器中打包和…...
ElasticSearch介绍+使用
ElasticSearch 1.背景 ElasticSearch的最明显的优势在于其分布式特性,能够扩展到上百台服务器,极大地提高了服务器的容错率。在大数据时代背景下,ElasticSearch与传统的数据库相比较,能够应对大规模的并发搜索请求,同…...
Redis——常用数据类型List
目录 List列表常用命令lpushlpushxrpushrpushlrangelpoprpoplindexlinsertllenlremltrim key start stoplset 阻塞版本命令blpopbrpop list的编码方式list的应用 List列表 Redis中的list相当于数组,或者 顺序表,一些常用的操作可以通过下面这张图来理解…...
前端基础知识+算法(一)
文章目录 算法二分查找条件注意方式基本原理左闭右闭正向写法 左闭右开正向写法 前端基础知识定时器及清除盒子垂直水平居中的方式垂直水平1.flex布局2.grid布局3.定位对于块级元素 解决高度塌陷的方式1.给父元素一个固定的高度2.给父元素添加属性 overflow: hidden;3.在子元素…...
photozoom classic 9解锁码2024年最新25位解锁码
photozoom classic 9 破解版顾及比恐龙还要稀有,我曾经和你一样一直再找,找了好几个月,也没有找到真的破解版,下载很多次, 都是病毒插件之类的 我昨天下了几次,没有一个不附带插件病毒木马的.......&#x…...
Oracle发邮件功能:设置的步骤与注意事项?
Oracle发邮件配置教程?如何实现Oracle发邮件功能? Oracle数据库作为企业级应用的核心,提供了内置的发邮件功能,使得数据库管理员和开发人员能够通过数据库直接发送邮件。AokSend将详细介绍如何设置Oracle发邮件功能。 Oracle发邮…...
优化理论及应用精解【9】
文章目录 二次型函数二次型函数详细解释一、定义二、性质三、应用四、示例五、图表辅助说明(由于文本限制,无法直接提供图表) “西尔维斯特准则”一、定义二、来源三、应用场景 参考文献 二次型函数 二次型函数详细解释 一、定义 二次型函…...
nginx实现https安全访问的详细配置过程
文章目录 前言什么是 HTTP?什么是 HTTPS?HTTP 和 HTTPS 的区别为什么 HTTPS 被称为安全的?配置过程配置自签名证书 前言 首先我们来简单了解一下什么是http和https以及他们的区别所在. 什么是 HTTP? HTTP,全称为“超…...
1. TypeScript基本语法
TypeScript 学习总结 TypeScript 是一种 JavaScript 的超集,增加了静态类型检查和编译时错误检测,从而提高了代码的可维护性和可靠性。以下是 TypeScript 的基础知识总结,包括语法、运算符、数据类型、变量声明和作用域。 ## 基本语法TypeS…...
C# UDP与TCP点发【速发速断】模式
1、UDP 客户端 //由于收发都在本机,所以只用一个IP地址 IPAddress addr IPAddress.Parse("127.0.0.1"); var ptLocal new IPEndPoint(addr,9001);//本机节点,用于发送var ptDst new IPEndPoint(addr,9002);//目标节点…...
pikachu下
CSRF(跨站请求伪造) CSRF(get) url变成了这样了,我们就可以新开个页面直接拿url去修改密码 http://pikachu-master/vul/csrf/csrfget/csrf_get_login.php?username1&password2&submitLogin CSRF(post) 这里只是请求的方式不同,…...
Go语言开发im-websocket服务和vue3+ts开发类似微信pc即时通讯
前言 IM即时通讯聊天, 为软件开发者打造,不依赖第三方sdk,完全用Go语言开发即时通讯服务,支持H5、Electron、Wails 、Uniapp和各种小程序的IM即时通讯, 快速实现私聊、群聊、在线客服!让你快速搭建一个微信聊天系统,打…...
高效批量获取抖音无水印视频:从概念到实战的完整指南
高效批量获取抖音无水印视频:从概念到实战的完整指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback suppor…...
如何用轻量级工具替代Armoury Crate实现华硕笔记本性能优化
如何用轻量级工具替代Armoury Crate实现华硕笔记本性能优化 【免费下载链接】g-helper Lightweight, open-source control tool for ASUS laptops and ROG Ally. Manage performance modes, fans, GPU, battery, and RGB lighting across Zephyrus, Flow, TUF, Strix, Scar, an…...
从作业到考试:中科大数字图像分析(DIA)课程避坑与自学指南
中科大数字图像分析(DIA)课程高效学习与实战避坑指南 数字图像分析(DIA)作为中科大电子工程与信息科学系的专业基础课,以其知识面广、难度高著称。每年都有不少同学因低估课程强度而陷入"上课听不懂、作业不会做、考前突击难"的困境。本文将系统梳理从日常…...
Microsoft团队提出“弯曲雅各布天梯”新思路,了解量子数据如何教会AI做更好的化学
来源:ScienceAI 本文约3500字,建议阅读5分钟量子计算机生成精确数据,AI模型学习并实现百万倍加速预测。有时,一个视觉上引人注目的隐喻,足以让你传达一个复杂的观点。2001 年夏天,杜兰大学物理教授 John P.…...
BililiveRecorder工具箱深度解析:专业级FLV直播录制文件修复解决方案
BililiveRecorder工具箱深度解析:专业级FLV直播录制文件修复解决方案 【免费下载链接】BililiveRecorder 录播姬 | mikufans 生放送录制 项目地址: https://gitcode.com/gh_mirrors/bi/BililiveRecorder BililiveRecorder工具箱提供了一套完整的直播录制文件…...
如何快速获取B站直播推流码:摆脱直播姬限制的终极指南
如何快速获取B站直播推流码:摆脱直播姬限制的终极指南 【免费下载链接】bilibili_live_stream_code 用于在准备直播时获取第三方推流码,以便可以绕开哔哩哔哩直播姬,直接在如OBS等软件中进行直播,软件同时提供定义直播分区和标题功…...
预警风波再起!这本物联网顶刊从中科院1区TOP跌落后,投稿风险几何?
1. 物联网顶刊降级风波:事实与传闻的边界 最近学术圈里关于《IEEE Internet of Things Journal》的讨论热度不减,这本曾经的中科院1区TOP期刊降级为2区的消息,叠加可能被列入预警名单的传闻,让不少准备投稿的研究人员心里打鼓。作…...
2026网站制作公司到底哪家好?国内主流PC网站建设服务公司排名
2026年1月,最新修订的《网络安全法》正式施行,叠加《网络数据安全管理条例》《个人信息保护法》细则落地,数据合规已成为网站建设的前置准入门槛。据中国互联网协会数据显示,2025年国内中大型企业官网合规整改率仅41.7%࿰…...
别再到处找教程了!Linux服务器上保姆级搭建YApi接口管理平台(含Node.js 12.13.0 + MongoDB 7.0.14配置)
企业级YApi私有化部署实战:从零构建高可用接口管理平台 在数字化转型浪潮中,API已成为企业系统互联的核心纽带。根据Postman 2023年度报告,超过82%的中大型企业正在使用专门的API管理工具来提升开发协作效率。YApi作为国产开源API管理平台的佼…...
网盘提速工具终极指南:直链解析技巧与多平台实战方案
网盘提速工具终极指南:直链解析技巧与多平台实战方案 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云…...
