java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > LongAdder原理

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

作者:fjkxyl

这篇文章主要介绍了高并发计数器LongAdder 实现原理与使用场景详解,通过理解 LongAdder 的设计哲学和实现细节,开发者可以在高并发场景中做出更优的技术选型,在保证线程安全的前提下实现 5-10 倍的性能提升,需要的朋友可以参考下

LongAdder 原理与应用详解

一、设计背景与核心思想

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

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. 分段累加流程

3. 伪共享解决方案

| Cell1 (64字节) | Cell2 (64字节) | ... |

三、关键操作解析

1. 累加操作(add)

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

执行策略

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;
}

特点

四、示例

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("最终计数: " + counter.sum()); // 应输出100000
    }
}

五、性能对比数据

测试环境:

实现方案耗时 (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原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文