遵化市城乡建设局网站浙江省建设信息港岗位证书查询

张小明 2026/1/2 0:25:35
遵化市城乡建设局网站,浙江省建设信息港岗位证书查询,树枝seo,太原网站建设公司招聘要彻底理解 ConcurrentHashMap 的 size() 流程#xff0c;核心是抓住不同JDK版本的设计差异#xff08;JDK7基于分段锁#xff0c;JDK8基于无锁计数#xff09;#xff0c;以及「并发下计数准确性」与「性能」的平衡思路。以下是分版本的详细拆解#xff1a; 一、核心背景…要彻底理解ConcurrentHashMap的size()流程核心是抓住不同JDK版本的设计差异JDK7基于分段锁JDK8基于无锁计数以及「并发下计数准确性」与「性能」的平衡思路。以下是分版本的详细拆解一、核心背景为什么size()不能简单累加ConcurrentHashMap的核心优势是无全局锁支持高并发读写。如果直接加全局锁统计元素个数会丧失并发优势如果不加锁直接累加又会因并发修改导致计数不准。因此size()的设计目标是在尽可能少的锁开销下获取足够准确的元素个数注意返回的是「近似值」非绝对精确。二、JDK7版本基于Segment分段锁的size()流程1. JDK7 ConcurrentHashMap 结构基础JDK7的核心是「分段锁Segment」整个容器分为多个Segment默认16个每个Segment是一个独立的哈希表继承ReentrantLock自身维护一个count变量记录该Segment内的元素个数并发读写时仅锁定单个Segment不同Segment的操作互不阻塞。2. size() 具体执行流程size()的本质是累加所有Segment的count值流程分「轻量级尝试」和「重量级加锁」两步步骤操作逻辑目的1. 轻量级尝试最多3次① 遍历所有Segment不加锁逐个读取Segment.count并累加得到总和sum1② 再次遍历累加得到sum2③ 第三次遍历累加得到sum3避免一上来加全局锁利用“短时间内无并发修改”的概率提升性能2. 判断尝试结果如果sum1 sum2 sum3说明3次累加过程中无并发修改计数准确直接返回该值如果不一致说明有线程在并发添加/删除元素进入「重量级加锁」3次是经验值平衡“重试开销”和“锁开销”3. 重量级加锁① 遍历所有Segment调用Segment.lock()加锁全局锁所有Segment被锁定② 重新遍历所有Segment累加count值③ 遍历完成后调用Segment.unlock()解锁④ 返回最终累加结果保证计数绝对准确但牺牲了并发性能仅在轻量级尝试失败时触发3. JDK7 size() 关键细节count是volatile变量每个Segment的count用volatile修饰保证单个Segment的计数可见性为什么最多试3次如果重试次数太少容易误触发全局锁次数太多重试本身的开销会超过锁开销3次是JDK团队的经验最优值性能特点低并发下无修改仅遍历3次无锁开销高并发下有修改触发全局锁性能下降。三、JDK8版本基于无锁计数的size()流程推荐重点掌握1. JDK8 ConcurrentHashMap 结构基础JDK8彻底取消了Segment核心结构改为「数组链表红黑树」并发控制依赖CAS synchronized桶级锁计数逻辑借鉴了LongAdder的思想分段计数核心是baseCount CounterCell[]。2. 计数核心组件组件作用特性baseCountvolatile long基础计数值无并发竞争时直接CAS更新该值效率最高CounterCell[]数组分段计数值当CAS更新baseCount失败有竞争将增量哈希到某个CounterCell更新该Cell的值避免所有线程竞争同一个变量modCountvolatile int修改计数器记录容器的修改次数添加/删除元素时1用于判断size()累加过程中是否有并发修改3. size() 具体执行流程JDK8的size()是mappingCount()的简化版size()返回int可能溢出mappingCount()返回long推荐使用流程如下graph TD A[初始化总和sum0] -- B[累加baseCount到sum] B -- C{CounterCell数组是否非空} C -- 是 -- D[遍历CounterCell数组累加每个Cell的value到sum] C -- 否 -- E[检查并发修改] D -- E[检查modCount是否变化是否有并发修改] E -- 有修改 -- A[重试累加自旋] E -- 无修改 -- F[返回sum]分步拆解基础累加先将baseCount基础计数的值累加到总和sum分段累加如果CounterCell[]非空说明有并发竞争遍历数组将每个CounterCell的value分段计数累加到sum并发校验检查累加过程中modCount是否变化若变化说明有线程在添加/删除元素计数可能不准自旋重试如果检测到并发修改重新执行「基础累加分段累加」直到无修改或重试次数足够返回结果返回最终的sum近似值累加过程中可能仍有线程修改但误差可接受。4. JDK8 size() 核心设计亮点无锁计数全程无全局锁仅通过CAS和自旋保证计数准确性符合JDK8“减少锁依赖”的设计思路分段计数CounterCell借鉴LongAdder将计数压力分散到多个Cell避免所有线程竞争同一个baseCount并发计数性能比JDK7提升一个量级近似值妥协放弃“绝对精确”换取“无锁高性能”——因为并发场景下size()的绝对精确无实际意义返回值的瞬间元素个数可能已变化。四、JDK7 vs JDK8 size() 核心差异对比维度JDK7JDK8核心依赖Segment.count 分段锁baseCount CounterCell[] CAS锁开销低并发无锁高并发全局锁全程无锁仅自旋计数准确性轻量级尝试失败后加锁保证绝对准确始终返回近似值误差可控性能高并发下因全局锁性能下降高并发下仍保持高性能分段计数核心思想「锁分段」→ 减少锁范围「无锁分段计数」→ 彻底无锁五、面试官常追问的关键细节1. size() 返回的是精确值吗JDK7轻量级尝试失败后加全局锁返回精确值轻量级尝试成功时返回“近似精确值”3次累加一致大概率无修改JDK8始终返回近似值累加过程中可能有线程修改但误差极小满足绝大多数业务场景如监控、统计。2. JDK8为什么用CounterCell而不是SegmentJDK8取消Segment的核心是「细化锁粒度」从Segment级→桶级而CounterCell是「计数维度的分段」与存储结构解耦Segment是“存储锁”的分段CounterCell仅负责“计数”的分段CounterCell的数量可动态扩展按需创建而Segment数量固定默认16更灵活。3. JDK8为什么推荐用mappingCount()替代size()size()返回int类型最大值为2^31-1约21亿当ConcurrentHashMap元素超过该值时会溢出mappingCount()返回long类型无溢出风险语义与size()完全一致。4. 计数时如何保证线程安全baseCount和CounterCell.value都是volatile修饰保证可见性更新baseCount时用CASUnsafe.compareAndSwapLong更新CounterCell时也用CAS避免线程冲突遍历CounterCell时通过Unsafe直接访问内存保证遍历过程的原子性。六、总结ConcurrentHashMap的size()流程本质是并发场景下“计数准确性”与“性能”的权衡JDK7先无锁重试失败后加全局锁兼顾“低并发性能”和“高并发准确性”JDK8彻底无锁基于分段计数CounterCell返回近似值极致优化高并发性能核心思想并发容器的计数无需绝对精确优先保证读写性能这也是ConcurrentHashMap与Hashtable全表锁计数的核心区别。------------------------------------------------------------------------------------------------------要彻底讲清ConcurrentHashMap的size()执行过程我们分JDK7分段锁和JDK8无锁分段计数两个版本展开且聚焦「代码级的具体执行步骤 底层原理」而非仅框架性描述。前置说明size()的核心目标是在并发读写场景下以最小的性能开销获取元素个数JDK7 兼顾“精确性”JDK8 优先“高性能”放弃绝对精确。先明确两个版本的核心计数载体版本核心计数变量并发控制方式JDK7每个Segment内置volatile int count记录该分段的元素数分段锁ReentrantLockJDK8baseCount基础计数volatile long CounterCell[]分段计数数组每个元素是volatile long valueCAS 自旋 无锁一、JDK7 版本基于 Segment 分段锁的 size() 详细流程1. JDK7 底层结构回顾ConcurrentHashMap被拆分为16个默认Segment可通过构造参数调整每个 Segment 是独立的哈希表且继承ReentrantLock分段锁。每个 Segment 有volatile int count记录该分段内的元素个数volatile保证单个分段计数的可见性新增/删除元素时仅锁定目标 Segment修改其countsize()需累加所有 Segment 的count。2. size() 完整执行步骤附伪代码publicintsize(){// 步骤1定义核心变量finalSegmentK,V[]segmentsthis.segments;intsum;// 最终累加结果intretries-1;// 重试次数初始-1标记首次尝试// 步骤2轻量级无锁尝试最多3次for(;;){if(retries3){// 重试3次失败触发重量级加锁// 步骤3全局加锁锁定所有Segmentfor(inti0;isegments.length;i){segments[i].lock();// 逐个锁定Segment全局锁}break;// 跳出循环准备累加}sum0;// 每次尝试重置总和intcheck0;// 校验值记录修改次数防并发修改// 步骤4遍历所有Segment无锁累加countfor(inti0;isegments.length;i){SegmentK,Vsegsegments[i];if(seg!null){sumseg.count;// 读取volatile count累加checkseg.modCount;// modCount该Segment的修改次数增/删元素1}}// 步骤5校验是否有并发修改check0 表示所有Segment都无修改if(check0){break;// 无修改计数准确跳出循环}// 有修改 → 重试进入下一轮for循环}// 步骤6若加了全局锁需解锁if(retries3){for(inti0;isegments.length;i){segments[i].unlock();// 逐个解锁Segment}}// 步骤7返回结果int可能溢出JDK7后期新增了long size64()returnsum;}3. 每一步的细节拆解步骤2轻量级无锁尝试最多3次为什么是3次JDK团队的经验值3次重试的开销 全局加锁的开销且3次内大概率能遇到“无并发修改”的窗口期每次尝试都会重新遍历所有Segment读取最新的count因为count是volatile读取的是内存最新值。步骤4累加 count 校验 modCountmodCount是每个 Segment 的修改计数器增/删元素时原子1check累加所有 Segment 的modCount若check0所有 Segment 自本次尝试开始后无任何修改sum是准确值若check≠0有 Segment 被并发修改sum可能不准触发重试。步骤3全局加锁重试3次失败后锁定所有 Segment此时所有增/删操作都会被阻塞因为增/删需要先锁对应 Segment加锁后重新累加count此时无并发修改sum是绝对精确值。步骤6解锁必须保证“加锁的Segment全部解锁”否则会导致后续所有操作阻塞死锁风险。4. JDK7 size() 关键特性低并发场景3次内大概率check0无锁开销性能极高高并发场景重试3次失败后加全局锁性能骤降但保证计数精确结果返回值要么是“无修改的精确值”要么是“加锁后的精确值”。二、JDK8 版本基于无锁分段计数的 size() 详细流程重点1. JDK8 底层结构回顾取消 Segment核心结构为「数组链表红黑树」并发控制依赖CAS synchronized桶级锁计数逻辑借鉴LongAdder将计数分散到baseCount和CounterCell[]避免所有线程竞争同一个变量。2. 核心计数变量先理解“写计数”再理解“读计数”size()是“读计数”需先知道增/删元素时“写计数”的逻辑才能理解读取流程变量类型作用写计数逻辑增/删元素时baseCountvolatile long基础计数无并发竞争时直接 CAS 更新baseCount1/-1CAS 失败则走CounterCellcounterCellstransient volatile CounterCell[]分段计数数组1. 计算当前线程的哈希值ThreadLocalRandom.getProbe()定位到数组中的一个CounterCell2. CAS 更新该CounterCell的value1/-13. 若数组未初始化/目标 Cell 为 null初始化数组并创建 Cell4. 若 CAS 仍失败重新计算哈希值重试避免哈希冲突modCountvolatile int修改计数器每次增/删元素时modCount用于校验读取过程中是否有并发修改CounterCell静态内部类分段计数单元仅含一个volatile long value字段保证计数可见性3. size() 完整执行步骤附伪代码 逐行解释JDK8 中size()是mappingCount()的简化版size()返回 int可能溢出mappingCount()返回 long推荐使用核心逻辑一致publiclongmappingCount(){// 步骤1初始化变量longsum0L;// 最终累加结果longcheck0L;// 校验用的modCount快照intretries-1;// 重试次数// 步骤2获取计数核心组件通过Unsafe直接访问底层变量CounterCell[]cscounterCells;// 步骤3自旋累加直到无并发修改或重试足够for(;;){if(retries1){// 重试1次失败放弃modCount校验避免无限自旋break;}sum0L;// 重置总和checkmodCount;// 记录当前modCount快照// 步骤4累加baseCount基础计数sumbaseCount;// 步骤5累加CounterCell数组分段计数if(cs!null){for(CounterCellc:cs){// 遍历所有非空Cellif(c!null){sumc.value;// 读取volatile value累加}}}// 步骤6校验是否有并发修改modCount未变 → 无修改if(modCountcheck){break;// 无修改跳出循环}// 有修改 → 自旋重试进入下一轮for循环}// 步骤7返回累加结果近似值returnsum;}4. 每一步的细节拆解步骤1变量初始化sum最终返回的元素个数初始为0check记录读取开始时的modCount用于后续校验retries重试次数初始为-1首次循环retries变为0重试1次后变为1触发跳出。步骤3自旋累加核心自旋的目的尽可能获取“无并发修改”的计数结果仅重试1次JDK8 认为“近似值足够”过多重试会浪费性能即使返回近似值误差也极小。步骤4累加 baseCountbaseCount是volatile类型读取时直接获取内存最新值无锁开销若并发度低无线程竞争counterCells为 nullsum就是baseCount直接返回。步骤5累加 CounterCell 数组遍历counterCells时仅读取非空 Cell 的valuevalue是 volatile保证最新遍历过程中可能有线程修改 Cell 的value但因为是“读取”无需加锁仅会导致 sum 是“瞬时近似值”。步骤6校验 modCountmodCount是volatile类型读取的是最新值若modCount check说明从“记录check”到“累加完成”的过程中无线程增/删元素sum 是“准精确值”若modCount ! check说明有并发修改自旋重试1次若重试后仍有修改直接返回当前 sum放弃精确性。步骤7返回结果结果是近似值即使modCount未变累加过程中也可能有线程修改baseCount/CounterCell因为读取是“非原子的遍历”但误差在高并发下可忽略为什么放弃绝对精确并发场景下size()返回值的瞬间元素个数可能已变化绝对精确无业务意义不如优先保证性能。5. JDK8 size() 关键细节补充1CounterCell 的哈希定位逻辑线程更新CounterCell时通过ThreadLocalRandom.getProbe()获取当前线程的“探针值”哈希值再通过probe (cs.length - 1)定位到数组下标类似哈希表的取模避免所有线程竞争同一个 Cell。2Unsafe 工具类的作用baseCount、counterCells、modCount都是通过Unsafe类直接操作内存地址更新/读取绕过 JVM 层面的锁保证操作的原子性和性能。3为什么 JDK8 不考虑加锁JDK8 的设计理念是“并发容器的计数无需绝对精确”业务场景中size()多用于“监控/统计/限流阈值判断”近似值足够加锁会阻塞所有增/删操作违背ConcurrentHashMap“高并发”的核心设计目标。三、两个版本 size() 过程的核心差异总结维度JDK7 执行过程JDK8 执行过程核心动作无锁重试3次 → 失败则全局加锁 → 精确累加无锁自旋1次 → 累加 baseCount CounterCell → 近似返回锁开销低并发无锁高并发全局锁性能骤降全程无锁仅自旋性能无损耗结果特性绝对精确加锁后/ 准精确无锁重试成功始终近似误差可控底层依赖Segment 的 countvolatile ReentrantLockbaseCount CounterCellvolatile CAS Unsafe性能优先级精确性 性能性能 精确性四、面试官常追问的“细节中的细节”1. JDK7 中如果 Segment 被扩容size() 会出错吗不会。Segment 扩容是“分段扩容”仅扩容当前 Segment扩容过程中该 Segment 的count仍会正确更新扩容时先加锁再迁移元素最后更新 countsize() 读取的是扩容后的 count。2. JDK8 中 CounterCell 数组是怎么初始化的首次 CAS 更新baseCount失败时会通过fullAddCount()方法初始化counterCells先尝试 CAS 创建长度为2的数组若仍有竞争数组会按2倍扩容类似 HashMap 扩容避免哈希冲突。3. size() 返回的“近似值”误差有多大极端场景下百万级并发增/删误差可能在“个位数到百位数”之间但常规业务场景万级并发误差几乎可以忽略通常≤10。4. 如何在 JDK8 中获取绝对精确的元素个数若业务必须精确可手动加全局锁不推荐// 不推荐会阻塞所有并发操作丧失ConcurrentHashMap的优势synchronized(concurrentHashMap){longexactSizeconcurrentHashMap.mappingCount();}替代方案业务层面通过“分布式计数器”如 Redis记录元素个数而非依赖size()。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

信息门户网站建设报价在线报名网站建设

如何快速掌握OpenCLIP:多模态AI的完整实践指南 【免费下载链接】open_clip An open source implementation of CLIP. 项目地址: https://gitcode.com/GitHub_Trending/op/open_clip 想要在AI领域脱颖而出?OpenCLIP作为多模态对比学习的开源实现&a…

张小明 2025/12/31 16:50:46 网站建设

建网站需要什么技术济南的企业网站

MBA必看!8个降AIGC工具推荐,高效应对AI检测 AI降重工具:让论文更“自然”,让学术更“真实” 在当前的学术环境中,AI生成内容(AIGC)已经成为论文写作中不可忽视的一部分。许多MBA学生在撰写论文…

张小明 2025/12/31 16:50:48 网站建设

开发网页多少钱河南百度关键词优化排名软件

本系统(程序源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容一、选题背景 关于电影信息聚合与评价问题的研究,现有研究主要以单一票房预测、情感分析或推荐算法优化为主,专门针…

张小明 2025/12/31 16:50:47 网站建设

禹城网站定制有哪些企业网站平台

目录具体实现截图项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理具体实现截图 本系统(程序源码数据库调试部署讲解)带文档1万字以上 同行可拿货,招校园代理 实验室设备管理系统vue Thinkphp和Laravel 项目开发技术介…

张小明 2025/12/31 16:50:46 网站建设

上海市网站设计公司郑州一建董事长

MeloTTS多语言语音合成系统容器化部署技术指南 【免费下载链接】MeloTTS 项目地址: https://gitcode.com/GitHub_Trending/me/MeloTTS 技术背景与需求分析 在当今全球化应用开发环境中,多语言语音合成技术已成为智能交互系统的核心组件。传统语音合成方案在…

张小明 2025/12/31 16:50:49 网站建设

呼市网站制作密云重庆网站建设

YOLO模型缓存击穿防御:互斥锁与双重检查机制 在现代工业视觉系统中,实时目标检测的稳定性往往决定了整个产线的运行效率。想象这样一个场景:一条自动化质检流水线上,数十台摄像头同时触发图像采集,瞬间涌入上百个推理请…

张小明 2025/12/31 16:50:50 网站建设