开发者

高并发计数器LongAdder 实现原理与使用场景详解

目录
  • LongAdder 原理与应用详解
  • 一、设计背景与核心思想
    • 1. 传统原子类的性能瓶颈
    • 2. LongAdder 设计目标
  • 二、实现原理剖析
    • 1. 核心数据结构
    • 2. 分段累加流程
    • 3. 伪共享解决方案
  • 三、关键操作解析
    • 1. 累加操作(add)
    • 2. 取值操作(sum)
  • 四、示例
    • 五、性能对比数据
      • 六、应用场景指南
        • 七、实现原理总结

          LongAdder 原理与应用详解

          一、设计背景与核心思想

          1. 传统原子类的性能瓶颈

          • AtomicInteger/AtomicLong 基于 CAS 实现
          • 高并发场景缺陷
            • CAS 失败率随竞争加剧指数上升
            • CPU 空转消耗大量资源
            • 缓存一致性流量(MESI协议)导致总线风暴

          2. LongAdder 设计目标

          • 降低竞争:通过数据分片分散写压力
          • 空间换时间:牺牲部分内存换取更高吞吐
          • 最终一致性:允许读取结果存在短暂误差

          二、实现原理剖析

          1. 核心数据结构

          // 基础值(无竞争时直接操作)
          transient volatile long base;
          // 分片单元数组(应对高并发)
          transient volatile Cell[] cells;
          // 分片单元结构(避免伪共享)
          @jdk.internal.vm.annotation.Contended
          static final class Cell {
              volatile long value;
              Cell(long x) { value = x; }
          }

          2. 分段累加流程

          高并发计数器LongAdder 实现原理与使用场景详解

          高并发计数器LongAdder 实现原理与使用场景详解

          3. 伪共享解决方案

          • 问题根源:不同线程的变量共享同一缓存行(通常 64 字节)
          • 优化方案
            • 使用 @Contended 注解自动填充
            • 每个 Cell 独占缓存行
            • 内存布局示意:
          | Cell1 (64字节) | Cell2 (64字节) | .编程客栈.. |

          三、关键操作解析

          1. 累加操作(add)

          public void add(long x) {
              Cell[] cs; long b, v; int m; Cell c;
              if ((cs yRVRoM= cells) != null || 
                  !casBase(b = base, b + x)) {
                  boolean uncontended = true;
                  if (cs == null || (m = cs.length - 1) < 0 ||
                      (c = cs[getProbe() & m]) == null ||
                    javascript  !(uncontended = c.cas(v = c.value, v + x)))
                      longAccumulate(x, null, uncontended);
              }
          }

          执行策略

          • 优先尝试更新 base
          • 失败后定位到线程对应的 Cell
          • 多级失败后触发数组扩容

          2. 取值操作(sum)

          public long sum() {
              Cell[] cs = cells;
              long sum = base;
              if (cs != null) {
                  for (Cell c : cs)
                      if (c != null) sum += c.value;
              }
              return sum;
          }

          特点

          • 非原子快照(可能包含进行中的更新)
          • 时间复杂度 O(n)(需遍历所有 Cell)

          四、示例

          import Java.util.concurrent.ExecutorService;
          import java.util.concurrent.Executors;
          import java.util.concurrent.TimeUnit;
          import java.util.concurrent.atomic.LongAdder;
          public class SimpleLongAdderExample {
              public static void main(String[] args) throws InterruptedException {
                  // 1. 创建LongAdder实例
                  LongAdder counter = new LongAdder();
                  // 2. 创建线程池(模拟并发请求)
                  ExecutorService executor = Executors.newFixedThreadPool(10);
                  // 3. 提交100个累加任务
                  for (int i = 0; i < 100; i++) {
                      executor.submit(() -> {
                          // 每个任务累加1000次
                          for (int j = 0; j < 1000; j++) {
                              counter.increment(); // 等同于add(1)
                          }
                      });
                  }
                  // 4. 关闭线程池并等待任务完成
                  executor.shutdown();
                  executor.awaitTermination(1, TimeUnit.MINUTES);
                  // 5. 输出最终结果
                  System.out.println("最终计数: " + counteryRVRoM.sum()); // 应输出100000
              }
          }

          五、性能对比数据

          测试环境:

          • CPU:8 核 Intel i9-9900K
          • 内存:32GB DDR4
          • JVM:OpenJDK 17
          • 测试用例:32 线程执行 1 亿次累加
          实现方案耗时 (ms)吞吐量 (ops/ms)内存占用
          synchronized4,52022,123
          AtomicLong1,28078,125
          LongAdder235425,531
          ThreadLocal 优化182549,450

          六、应用场景指南

          1. 推荐使用场景

          场景类型典型用例优势说明
          高频计数器网站 PV/UV 统计分散写竞争
          监控指标采集QPS/TPS 统计允许最终一致性
          分布式限流令牌桶算法实现避免 CAS 失败风暴
          大数据聚合实时计算中间结果支持快速并行累加

          2. 不适用场景

          场景类型典型用例问题分析
          精确原子操作库存扣减sum() 非原子快照
          读多写少配置项更新AtomicLong 更高效
          内存敏感场景海量独立计数器Cell 数组内存开销大

          七、实现原理总结

          设计要点实现方案解决的问题
          竞争分散分片 Cell 数组降低 CAS 失败率
          伪共享预防@Contended 注解提升缓存利用率
          动态扩容按需创建 Cell平衡性能与内存
          延迟初始化初始使用 base 变量减少内存开销
          最终一致性sum() 合并所有 Cell保证最终结果正确性

          通过理解 LongAdder 的设计哲学和实现细节,开发者可以在高并发场景中做出更优的技术选型,在保证线程安全的前提下实现 5-10 倍的性能提升。关键是要根据实际业务场景的读写编程客栈比例、一致性要求和资源限制进行合理选择。

          到此这篇关于高并发计数器LongAdder 实现原理与使用场景详解的文章就介绍到这了,更多相关LongAdder原理内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

          0

          上一篇:

          下一篇:

          精彩评论

          暂无评论...
          验证码 换一张
          取 消

          最新开发

          开发排行榜