Java并发进阶系列:深度讨论官方关于jdk1.8ConcurrentHashMap的resizeStamp源代码修复逻辑
前言首先给出以下open JDK版本的序号说明和Oracle JDK序号说明(1)对于JDK8或者Java 8即可指代openjdk-8-jdk或者java-1.8.0-openjdk,也可指代Oracle家的Java SE 8或者JDK 8u211 and later(1)对于JDK16或者Java 16即可指代openjdk的JDK 16.0.2 ,也可指代Oracle家的Java SE 16或者 jdk16.0.1,这里为何给出Java 8和Java 16版本说明?首先resizeStamp的bug在Java8出现,并在Java 12被修复,因此本文直接给出最新版Java 16作为bug修复前后对比即可。以下做个约定:统一以Java X形式作为版本称号,CHM:ConcurrentHashMap的简称,以此减少阅读障碍。在前面的文章中,关于Java 8 的CHM addCount方法里面分支2:resizeStamp和sc==rs+1、sc==rs+MAX_RESIZERS的讨论中,已经指出其bug嫌疑:privatefinalvoidaddCount(longx,intcheck){// 分支1 省略...// 分支2if(check=0){NodeK,V[]tab,nt;intn,sc;while(s=(long)(sc=sizeCtl)(tab=table)!=null(n=tab.length)MAXIMUM_CAPACITY){intrs=resizeStamp(n);// 注意这里计算出的rs是正值if(sc0){// sc是负值,怎么会等于rs+1或者rs + MAX_RESIZERS这个正值呢? 有可能是个bugif((scRESIZE_STAMP_SHIFT)!=rs||sc==rs+1||sc==rs+MAX_RESIZERS||(nt=nextTable)==null||transferIndex=0)break;if(U.compareAndSetInt(this,SIZECTL,sc,sc+1))transfer(tab,nt);}elseif(U.compareAndSetInt(this,SIZECTL,sc,(rsRESIZE_STAMP_SHIFT)+2))transfer(tab,null);s=sumCount();}}官方bug描述其实这个bug在open jdk的官方bugs主页已经给出相关解释和修复过程,链接:官方bug描述页面:从Detail这一块描述得到信息如下:bug的描述:ConcurrentHashMap.addCount()设计逻辑中可能存在bug。(这里虽然提到addCount()方法,但本人更想强调的是扩容分支的resizeStamp的bug)级别是:bug当前状态:已经修复影响的版本:Java 11、Java12在哪个版本得到修复:Java 12使用操作系统平台:所有bug页面创建时间:2018-11-26解决bug的最后时间:2018-12-11bug所属库:Java的核心库——core-libs提交者的修复建议In the above code, condition of (sc == rs + 1 || sc == rs + MAX_RESIZERS ) would never be true , since the value of rs is positive and the value of sc is negative .译:条件 (sc == rs + 1 || sc == rs + MAX_RESIZERS )永远不可能true,因为rs的值为正数,而sc值为负数并建议修改为:The correct condition should be (sc RESIZE_STAMP_SHIFT) == rs + 1 || (sc RESIZE_STAMP_SHIFT) == rs + MAX_RESIZERS, which can be used to dedect if resizing process finished or resizing threads reaches maxmium limitation译:正常的条件应该是这样: (sc RESIZE_STAMP_SHIFT) == rs + 1 || (sc RESIZE_STAMP_SHIFT) == rs + MAX_RESIZERS,这两个条件表示扩容任务已结束或者参与扩容的线程总数达到最大值确实,这个bug非常明显,以分支2作为说明int rs = resizeStamp(n),以容量n=16作为说明,rs计算为下面的值0000 0000 0000 0000 1000 0000 0001 1011考察低16位,rs+1的结果显然是一个正数0000 0000 0000 0000 1000 0000 0001 1100rs+MAX_RESIZERS同理也是一个正数,接着判断条件if(sc0)成立才能进入rs+1等条件,也即此时sc是一个负数(其实是因为首个扩容线程会将sc设为(rs RESIZE_STAMP_SHIFT) + 2的一个基础负数),基于此,有提交者在这里发现的了bug:sc是负数,而rs+1是正数,因此sc==rs+1永远不会成立官方关于此bug的讨论过程JCP JSR-166 Expert Group (关于Java并发编程的规范提案的专家组)几个相关成员的对话过程即可知道他们对问题的思考和处理方式。在Activity这个栏目就是用于提交者已经相关专家bug讨论过程,“All”是显示所有他们的活动记录,一般无需关注,“Comments”显示他们的对话过程,bug的讨论过程就在这里,因此需要重点关注,具体如下:以下是来自“Comments”区域的内容:(最开始由Webbug Group 这个小组提交了该issue - 2018-11-26 00:53)Stuart Marks 说:Stuart Marks added a comment - 2018-11-28 09:10Martin, can you take a look at this?Martin,来,帮我看看这个bug?Martin的回答,主要意思是:bug提交者在查一个确实是由addCount产生错误计数,但Martin说他们也没有可以使用的压测案例,并建议使用者用多线程做压测来让addCount的这个bug复现,但这个bug不好复现。Resizing the internal bucket array is hairy race-prone code, and hard to stress test because resizes are relatively rare.The reporter probably investigated an actual occurrence of incorrect count (we could ask!), but we don’t have a stress test reproduction that could be used.One should be able to construct a stress test using multiple threads to trigger concurrent attempts to addCount, but it won’t be easy.David Holmes 对Martin说:What is your analysis just based on the code and the report? It certainly appears incorrect to me.你的分析只是基于代码以及提交的报告?这个bug在我看来显然是不正确的。Martin回答David Holmes :Martin说自己也看了看源码但研究时间不够长,自己还没能搞懂其设计,然后说Doug应该记得这个设计!I stared at the code for a while, but not long enough to understand it. Doug will remember!Doug Lea added a comment - 2018-11-28 15:53:Doug Lea看到这个bug,做了基本的分析:这个bug会影响到CHM性能也即有些线程不能参与到扩容任务中,并指出这个bug只是影响性能而不是一个引起map发生错误的bug,指出这个bug需要修复。Yes. Some of this check now includes dead code, because of a change of representation at one point that wasn’t adjusted for. With the possible effect of some threads not helping resize (a performance, not map correctness bug) This should be fixed (and is committed in jdr166 repo):然后他贴出修复前后的源码diff---ConcurrentHashMap.java.~1.314.~2018-10-0513:42:39.860409607-0400+++ConcurrentHashMap.java2018-11-2818:48:55.998082379-0500@@-2307,9+2307,9@@(n=tab.length)MAXIMUM_CAPACITY){intrs=resizeStamp(n);if(sc0){-if((scRESIZE_STAMP_SHIFT

相关新闻

【Bug已解决】[Bug]: kv_cache_offloadig crashes on 0.21.0 - KeyError in self._block_id_to_pending_jobs[bid

【Bug已解决】[Bug]: kv_cache_offloadig crashes on 0.21.0 - KeyError in self._block_id_to_pending_jobs[bid

【Bug已解决】[Bug]: kv_cache_offloadig crashes on 0.21.0 - KeyError in self._block_id_to_pending_jobs[bid] 解决方案 一、现象长什么样 vLLM 0.21.0 开了 KV 缓存卸载(把冷 block 从显存搬到 CPU 内存/磁盘,腾显存给更热的请求&#x…

2026/10/6 12:47:50 阅读更多 →
级联H桥SVG无功补偿系统设计与电网不平衡解决方案

级联H桥SVG无功补偿系统设计与电网不平衡解决方案

1. 项目概述 在电力系统中,无功补偿是维持电网电压稳定、提高功率因数的关键技术手段。随着新能源大规模并网和电力电子设备普及,电网不平衡问题日益突出,传统无功补偿装置已难以满足现代电网需求。本项目聚焦于不平衡电网条件下的SVG&#x…

2026/10/12 16:56:46 阅读更多 →
ansible使用之——国产设备适配

ansible使用之——国产设备适配

ansible国产设备适配前言适配过程验证效果前言 ansible是美国redhat公司研发的一款开源的自动化运维工具,可以非常高效且可靠的实现对被控制端(服务器、网络设备等被控制节点)进行运维工作。然而,也同样由于此,其对国产…

2026/9/29 7:34:29 阅读更多 →

最新新闻

股债汇金四杀:买得分散,为什么还会一起亏?

股债汇金四杀:买得分散,为什么还会一起亏?

**分散买了股票、债券、美元和黄金,不等于分散了“急着用钱”的风险。**市场平静时,它们讲的是不同故事;资金紧张时,它们可能面对同一个问题:持有人必须把资产变成现金。 最近“股债汇金四杀”的说法很吓人。但对一个…

2026/10/13 3:21:48 阅读更多 →
就业指南|分析了近百份简历后,我决定写一篇就业指南

就业指南|分析了近百份简历后,我决定写一篇就业指南

本篇文章共 10000字,完全阅读全篇约10分钟 州弟学安全,只学有用的知识 前言 大家好,我是州弟。 大家还记得我上一篇文章吗?网安面试|记2026年8月国内某情报安全厂商面试的一次经历 ,当时分享了我主动投递并完整体验…

2026/10/13 3:21:48 阅读更多 →
[Java] 常用工具类

[Java] 常用工具类

日期相关类Date 类java.util.Date:Java 早期的日期时间类,精确到毫秒,用来表示一个特定的时刻常用成员方法可用方法:1)boolean after(Date when):判断当前日期是否在指定日期之后2)boolean befo…

2026/10/13 3:21:48 阅读更多 →
微信小程序打卡系统源码解析:前后端分离与MySQL表设计实战

微信小程序打卡系统源码解析:前后端分离与MySQL表设计实战

简介:这套基于小程序的互动打卡项目源代码,采用JavaSSM构建后端服务,前端基于uniapp/原生小程序开发,并配套MySQL 5.7数据库脚本,是一套完整可运行的前后端工程,适合Java学习者及毕业设计、课程设计参考。压…

2026/10/13 3:21:48 阅读更多 →
微信小程序互动打卡系统:MySQL表结构设计与前后端完整实现

微信小程序互动打卡系统:MySQL表结构设计与前后端完整实现

简介:这套基于小程序的互动打卡完整前后端源码,采用Java与SSM框架构建后端服务,搭配uniapp与原生小程序前端,适合毕业设计、课程设计或小程序开发学习者参考。资源共1248个文件,压缩包约8.77MB,核心包含Jav…

2026/10/13 3:21:48 阅读更多 →
CS231n KNN作业深度解析:从像素距离到视觉本质

CS231n KNN作业深度解析:从像素距离到视觉本质

1. 这不是“写个KNN”——而是用最朴素的代码照见计算机视觉的底层逻辑你点开CS231n作业1-Q1,看到“写一个K近邻分类器”,第一反应可能是:不就是算距离、排个序、投个票?抄几行numpy就完事了。我当年也是这么想的,直到…

2026/10/13 3:20:47 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →