如何利用 DoubleAdder 的分段计数器思想在极高并发场景下规避 CPU 的缓存行竞争

夜芳大大_1156

夜芳大大_1156

2026-04-24

536人浏览

原创

doubleadder不解决伪共享,其sum()在高并发下可能变慢,因需遍历cell数组且热点cell易引发缓存行竞争;真正规避需手动实现内存对齐的分段计数器。

如何利用 doubleadder 的分段计数器思想在极高并发场景下规避 cpu 的缓存行竞争

DoubleAdder 本身不解决伪共享,它只是 Java 提供的浮点累加器;真正规避缓存行竞争的是其底层设计思想——分段计数 + 内存隔离,这需要你手动实现或理解 LongAdder 的 Cell 布局逻辑。

为什么 DoubleAdder.sum() 在高并发下仍可能慢

DoubleAdder 是 JUC 中封装了 Striped64 的累加器,它内部用 Cell[] 存储分段值,但它的 sum() 方法必须遍历所有非空 Cell 并加总。问题在于:

  • 若线程数远超 CPU 核心数(比如 1000 个线程争抢 16 个 Cell),部分 Cell 会成为热点,触发伪共享
  • Cell 类虽有 @Contended 注解,但该注解仅在开启 -XX:-RestrictContended 且 JVM 支持时才生效;OpenJDK 8 默认不启用,JDK 9+ 需显式配置
  • 未对齐的 Cell 数组起始地址,会导致多个 Cell 落入同一缓存行——@Contended 没法救这个

如何手动构造一个真正隔离的分段 double 计数器

Java 没有 DoubleAdder 的裸 Cell API,所以得仿照 Striped64 自建。关键不是“用 double”,而是让每个线程写入的变量物理上独占缓存行:

  • 定义填充结构:static final class PaddedDouble { @sun.misc.Contended double value; }(注意:需 JDK 8u20+ 且 -XX:-RestrictContended)
  • 分配对齐数组:private final PaddedDouble[] cells = new PaddedDouble[4]; —— 全局静态或通过 Unsafe.allocateMemory + Unsafe.setMemory 手动对齐到 64 字节边界
  • 线程索引必须稳定:用 ThreadLocalRandom.current().nextInt(cells.length),而非简单取模,避免哈希冲突集中
  • 绝不复用 cells[i] 给多个线程:每个线程只写固定索引,靠扩容分散(类似 LongAdder 的 cellsBusy 机制)

堆上分配 PaddedDouble[] 时最易踩的对齐坑

即使每个 PaddedDouble 用 @Contended,若整个数组起始地址没对齐,第一个元素就可能跨缓存行,连带后续全部错位:

  • new PaddedDouble[4] 不保证数组首地址 64 字节对齐——JVM 堆分配器不提供此保证
  • Unsafe.allocateMemory(size) 返回地址也未必对齐,必须手动向上取整:long addr = (addr0 + 63) & ~63L;
  • 更稳妥的做法是用 ByteBuffer.allocateDirect() + Unsafe,或直接依赖 VarHandle(JDK 9+)配合 MemorySegment(JDK 14+)做显式对齐映射
  • 验证是否对齐:用 Unsafe.objectFieldOffset 查 cells[0] 地址,再对 64 取模,结果必须为 0

为什么不能只靠 alignas(64) 或 @Contended

这两个只是“声明意图”,不是“强制保障”:

  • alignas(64) 是 C++ 关键字,Java 里无效;@Contended 是 JVM 层语义,依赖运行时参数和版本支持
  • 即使字段对齐了,如果它所在对象被紧凑打包(比如 class A { @Contended long a; int b; }),b 仍可能和 a 共享缓存行
  • 真正的隔离必须满足:目标字段是所在缓存行内唯一被频繁写的变量,且该缓存行无其他写操作干扰——这意味着它最好是一个独立对象、独立分配、独立访问

实际压测中,哪怕只差一个字节没对齐,吞吐量可能下降 30% 以上。这不是理论风险,是硬件层面的确定性惩罚。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

11037

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

8142

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

7052

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1184

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

968

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1436

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

2909

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20191

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1275

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.9万人学习