当前位置: 首页 > news >正文

HashMap为什么线程不安全? ConcurrentHashMap如何保证线程安全? AQS如何实现锁的获取与释放?用男女关系进行解释,一看就懂

HashMap在多线程下容易出问题,主要是因为它的核心操作不是“原子”的,就像一对情侣同时往一个共享日记本里写秘密,很容易互相干扰。‌
💔 HashMap的线程不安全“情侣矛盾”
数据覆盖‌:当你们(线程A和B)同时往同一个位置写东西,如果时机不对,后写的人可能会把先写的人的内容给擦掉覆盖了。‌
扩容混乱‌:当日记本(HashMap)需要换更大的本子时(扩容),这个过程很复杂。如果这时还有人不停地往里写新内容,很容易导致一些记录丢失,或者本子里的索引(链表)打结,形成死循环。‌
计数出错‌:日记本里记录总数(size)的统计也不是一步完成的,你们同时写,最后总数可能比实际少记了。‌
🤝 ConcurrentHashMap的“默契协作”
ConcurrentHashMap解决了上面的问题,它采用了更聪明的分工方式,就像情侣间约定好分区管理日记本:
分段锁(JDK7)‌:把日记本分成很多个小格子,你们各自负责不同的格子,写自己格子里的内容时互不打扰,大大减少了冲突和等待。‌
CAS+synchronized(JDK8)‌:这种方式更灵活。对于空位置,尝试用“快速打招呼”(CAS)的方式直接写入;如果位置有人(发生哈希冲突),才用“小范围商量”(synchronized锁住链表头或树根)来协调。‌ 这就像看到想写的地方没人就直接写,有人才需要简单沟通一下。
🔑 AQS的“排队领证”机制
AQS(AbstractQueuedSynchronizer)是Java并发包中锁(如ReentrantLock)实现的核心,可以把它想象成民政局婚姻登记处的叫号系统,核心是一个“排队领证”的机制:
获取锁(尝试领证)‌:当一对情侣(线程)想来“领证”(获取锁)时,会先看一下当前窗口状态(state变量)。如果没人(state为0),他们就直接办理;如果有人在办(state不为0),他们就需要取号排队,进入等待队列。这个排队系统(CLH队列)保证了先来的先服务。
释放锁(办完离开)‌:当这对情侣办完手续,就会离开窗口(释放锁),同时系统(AQS)会通知排队中的下一对情侣(线程)来办理。
💡 给你的“恋爱”建议
如果你的“感情生活”(应用场景)中,“写日记”(修改Map)的操作比较多,那么使用ConcurrentHashMap会是更明智的选择,它能有效避免你们之间的“争吵”(数据不一致)。‌
对于更复杂的“感情约定”(同步控制),AQS提供的“排队机制”是一个非常强大和灵活的基础工具。

用男女关系解释AQS的排队领证机制

想象一下,‌AQS就是民政局婚姻登记处的核心叫号排队系统‌,而你们一对对情侣(‌线程‌)就是来办理结婚登记(‌获取锁‌)的。

1. 核心资源:结婚窗口 (The State)‌

民政局只有一个真正的结婚窗口(或者说,同一时间只允许一对情侣办理)。这个窗口的“空闲/忙碌”状态,就是AQS核心的 ‌state‌ 变量。

state = 0:窗口空闲,可以办理。

state = 1:窗口忙碌,正在为一对情侣服务。

2. 获取锁:尝试领证 (Acquiring the Lock)‌

现在,你和你的伴侣(‌线程A‌)来到民政局,想要领证。

第一步:直接尝试 (CAS操作)‌

你们不会直接冲上去,而是先彬彬有礼地看一眼窗口。发现窗口是空闲的 (state=0)。你们会‌快速而礼貌地‌(通过一次原子性的CAS操作)尝试把状态从“0”改成“1”,表示“这个窗口我们占了”。

成功‌:恭喜!你们立刻开始办理手续(‌线程A成功获取锁,进入临界区执行代码‌)。整个过程非常迅速,没有排队。

第二步:需要排队 (入队操作)‌

如果你们来的时候,窗口已经有人了 (state=1),或者在你尝试CAS的时候,另一对情侣(‌线程B‌)手更快,抢先占用了窗口(‌CAS失败‌)。

这时,你们不能傻站着干等。叫号系统(‌AQS‌)会给你们一个‌排队号‌,并请你们到‌等候区‌坐着(‌将线程A封装成一个Node节点,加入CLH队列的尾部‌)。

等候区的规矩‌:在排队时,你们不能不停地去问“到我们了吗?”,这样很烦人(‌避免了大量无用的CPU自旋‌)。正确的做法是:你们会安静地休息(‌线程进入等待阻塞状态 park()‌),但会关注前面那对情侣的动静。因为你知道,当前面的人办完,他们会来通知你(‌前驱节点会唤醒后继节点‌)。

3. 释放锁:办完离开 (Releasing the Lock)‌

经过一番甜蜜的填表、宣誓,窗口那对情侣(‌线程B‌)终于办完了所有手续。

第一步:腾出窗口‌

他们离开窗口,并且‌明确地‌通过系统把窗口状态重置为“空闲” (state 从 1 改回 0)。这就像把结婚证拿到手,然后对系统说:“我们好了,下一位!”

第二步:叫下一位‌

叫号系统(‌AQS‌)接收到这个信号后,不会胡乱喊人。它会严格按照排队顺序,去‌等候区找到排在最前面的那对情侣‌(‌队列头节点的后继节点,即下一个该被唤醒的线程‌),然后轻轻拍拍他们说:“轮到你们了,快去窗口吧!”(‌执行 unpark() 唤醒线程A‌)。

4. 公平 vs. 非公平的“插队”文化‌

这里就引出了AQS一个非常重要的特性:‌公平锁与非公平锁‌。

非公平锁 (默认情况,像现实生活)‌

当线程A被唤醒,走向窗口时,‌突然冲进来一对火急火燎的新情侣(线程C)‌!他们根本不看排队情况,直接冲到窗口前尝试CAS操作。

如果线程C成功了‌:它就“插队”成功了,线程A只能眼睁睁地看着,然后再次回到等候区排队。这虽然不公平,但‌效率高‌,因为它减少了线程切换的开销(线程C本来就在运行态,不用唤醒)。

公平锁 (理想的文明社会)‌

在这种模式下,系统有严格规定:‌必须按照排队顺序来‌。任何新来的情侣(线程C),即使看到窗口空闲,也必须先乖乖地去队尾取号排队。这样就保证了绝对的先来后到,杜绝了任何插队行为。

总结比喻‌

AQS 组件/概念 男女关系比喻

锁 / 共享资源‌ 民政局的‌结婚登记窗口‌

线程‌ 一对对来‌办理结婚登记的情侣‌

state 变量‌ 窗口的‌“空闲/忙碌”状态指示牌‌

CLH 队列‌ 民政局的‌等候区座位和排队顺序‌

CAS 操作‌ 情侣‌快速查看并尝试抢占空闲窗口‌的敏捷动作

获取锁成功‌ ‌成功占用窗口,开始办理结婚手续‌

获取锁失败‌ ‌需要取号,进入等候区休息等待‌

释放锁‌ ‌办完手续,离开窗口,并通知下一位‌

公平锁‌ ‌严格按排队顺序叫号,禁止插队‌

非公平锁‌ ‌允许新来的情侣在窗口空闲时尝试“插队”‌

所以,AQS的这套“排队领证”机制,完美地解决了多线程环境下,如何让众多请求者(情侣)有序、高效地访问稀缺资源(结婚窗口)的问题,既保证了秩序(公平性),又兼顾了效率(非公平性)。

 

 

http://www.dtcms.com/a/513408.html

相关文章:

  • 免费开源网站系统有哪些门户网站建设方案费用
  • 动易网站后台管理系统新昌县住房和城乡建设局网站
  • 网站切片 做程序数据分析师报名入口
  • 宿迁市网站建设口腔医院网站开发
  • Redis 特性/应用场景/通用命令
  • 学生个人网站建设模板网站为什么做站外推广
  • 零基础学网站建设 知乎长治长治那有做网站的
  • RPC服务
  • 北京外贸网站设计备案邯郸网页
  • 素马网站制作开发腾讯朋友圈广告怎么投放
  • 网站开发包括哪些网站推广怎么做
  • SwiftUI自定义一个水平渐变进度条
  • 电力电子技术 第四章——半导体功率器件
  • 网站运营专员具体每天怎么做wordpress音乐加载慢
  • 网站建设中图片是什么意思推特是谁的公司
  • 免费做手机网站有哪些wordpress注册邮箱收不到
  • 搜狗网站排名软件国内图片下载网站
  • wordpress 百度平台网站优化排名
  • 22.unordered_map和unordered_set的封装
  • 网站框架图片二维码生成器网页版
  • 做3d效果的网站wordpress中文问答模块
  • 杭州网站推广优化哪里好wordpress编辑文章更新失败
  • 工信部网站 地址呼伦贝尔网站建设维护
  • 帝国网站数据库配置文件网站建设程序员
  • 找别人做淘客网站他能改pid吗全网营销策划公司
  • 温州建设小学瓯江校区网站wordpress 订阅推送
  • 全屏网站帮助2021十条重大新闻
  • 自动识别手机和电脑版本网站阿里网站建设视频教程
  • 银行网站建设中优化大师下载电脑版
  • 网站建设的通知网站维护分工关键词爱站网关键词挖掘工具