尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Java并发进阶系列:深度讨论官方关于jdk1.8ConcurrentHashMap的resizeStamp源代码修复逻辑

Java并发进阶系列:深度讨论官方关于jdk1.8ConcurrentHashMap的resizeStamp源代码修复逻辑
📅 发布时间:2026/7/28 11:32:35
前言

首先给出以下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){Node<K,V>[]tab,nt;intn,sc;while(s>=(long)(sc=sizeCtl)&&(tab=table)!=null&&(n=tab.length)<MAXIMUM_CAPACITY){intrs=resizeStamp(n);// 注意这里计算出的rs是正值if(sc<0){// sc是负值,怎么会等于rs+1或者rs + MAX_RESIZERS这个正值呢? 有可能是个bugif((sc>>>RESIZE_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,(rs<<RESIZE_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-11

bug所属库: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 1100

rs+MAX_RESIZERS同理也是一个正数,接着判断条件if(sc<0)成立才能进入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:10

Martin, 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(sc<0){-if((sc>>>RESIZE_STAMP_SHIFT

相关新闻

  • Keil5 修改STM32单片机项目名称
  • NBM7100A芯片在物联网设备中的电源管理优化方案
  • Zookeeper--08---zk实现分布式锁、案例

最新新闻

  • 从推箱子到AI智能体评估:实战搭建LLM游戏测试环境
  • 2026年7月全新志高空调售后服务电话24小时400人工热线全面正式启用公告 - 全域品牌推荐
  • WordPress独立站成本全解析:从免费到企业级建站方案
  • 智能写作助手:跨学科文档自动适配技术解析
  • 魔兽争霸3现代电脑完美运行终极指南:5分钟解决闪退、卡顿、宽屏适配
  • GPT-5.5 Instant 更新解析:从智商到情商,AI 如何变得更懂你

日新闻

  • 力旷智能:伺服驱动系统在制药收瓶设备中的应用解析
  • 2026 网安入门避坑指南,零基础如何避开无效学习直接上手实战
  • 揭秘CFC项目:如何通过手机摄像头实现850kbps无网络文件传输

周新闻

  • 大连理工大学与东京大学联手打造的“主动型AI助手“
  • 170.2026年国家级科研瓶颈:超精密单点金刚石切削(SPDT)光学表面生成
  • SongBloom:革命性歌曲生成框架深度解析——如何通过交织自回归与扩散模型创作完整音乐

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号