java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java LongAdder

Java LongAdder原理解析与实战应用小结

作者:嘵奇

LongAdder是Java 8中java.util.concurrent.atomic包引入的高性能计数器类,专为高并发场景下的数值累加操作优化设计,本文给大家介绍Java LongAdder原理解析与实战应用小结,感兴趣的朋友一起看看吧

一、LongAdder概述

LongAdder是Java 8中java.util.concurrent.atomic包引入的高性能计数器类,专为高并发场景下的数值累加操作优化设计。在Java并发编程领域,它已成为解决伪共享和线程竞争问题的经典解决方案。

二、传统方案的局限性

在LongAdder出现之前,开发者通常使用以下两种方式实现计数器:

synchronized关键字

private long count = 0;
public synchronized void increment() {
    count++;
}

AtomicLong

AtomicLong counter = new AtomicLong();
public void increment() {
    counter.incrementAndGet();
}

传统方案的性能瓶颈:

三、LongAdder核心原理

3.1 分段计数设计

LongAdder采用分治策略,其核心数据结构是一个Cell数组:

transient volatile Cell[] cells;
transient volatile long base;

当没有竞争时,直接操作base值;出现竞争时,将不同线程映射到不同的Cell单元进行操作。

3.2 伪共享解决方案

每个Cell使用@Contended注解填充,防止CPU缓存行伪共享:

@sun.misc.Contended static final class Cell {
    volatile long value;
    // ...
}

3.3 动态扩容机制

初始状态下cells数组为null,首次竞争发生时初始化2个Cell,后续根据竞争情况按2的幂次扩容。

四、性能对比测试

使用JMH进行基准测试(单位:ops/ms):

线程数AtomicLongLongAdder
112,34510,204
43,21528,901
898745,672
1632452,189

测试结论:

五、实战应用示例

5.1 API请求统计

public class ApiMonitor {
    private final LongAdder successCount = new LongAdder();
    private final LongAdder errorCount = new LongAdder();
    private final LongAdder totalLatency = new LongAdder();
    public void recordSuccess(long latency) {
        successCount.increment();
        totalLatency.add(latency);
    }
    public void recordError() {
        errorCount.increment();
    }
    public MonitoringData getStats() {
        return new MonitoringData(
            successCount.sum(),
            errorCount.sum(),
            totalLatency.sum() / (double) successCount.sum()
        );
    }
}

5.2 分布式限流器

public class RateLimiter {
    private final LongAdder requestCount = new LongAdder();
    private final int maxRequests;
    public RateLimiter(int maxRequests) {
        this.maxRequests = maxRequests;
    }
    public boolean tryAcquire() {
        if(requestCount.sum() < maxRequests) {
            requestCount.increment();
            return true;
        }
        return false;
    }
    public void reset() {
        requestCount.reset();
    }
}

六、源码级优化分析

6.1 哈希算法优化

线程哈希值计算采用ThreadLocalRandom:

static final int getProbe() {
    return UNSAFE.getInt(Thread.currentThread(), PROBE);
}

6.2 惰性初始化策略

cells数组采用延迟初始化,避免不必要的内存开销:

if (cs == null || (m = cs.length - 1) < 0)
    init();

6.3 求和算法优化

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

七、使用注意事项

内存消耗

数值精度限制

求和一致性

// 非精确快照
long snapshot = adder.sum(); 
// 精确快照需要暂停所有线程(不现实)

八、扩展应用场景

九、未来演进方向

Java 17中引入的LongAccumulator提供了更灵活的累加方式:

LongAccumulator accumulator = new LongAccumulator(Long::sum, 0L);

总结

LongAdder通过创新的分段计数设计,在保证线程安全的前提下,将高并发写操作的性能提升了一个数量级。其设计思想对理解现代并发编程模式具有重要意义,适用于写多读少的计数器场景。开发者需要根据具体业务场景,在AtomicLong、LongAdder和锁机制之间做出合理选择。

到此这篇关于Java LongAdder原理解析与实战应用的文章就介绍到这了,更多相关Java LongAdder内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

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