你使用过 Java 的累加器吗?

Sherwin.Wei Lv7

你使用过 Java 的累加器吗?

回答重点

在 Java 中累加器(Accumulator)一般指的是LongAdderDoubleAdder 类,它们在高并发场景下比传统的 AtomicLong 更具优势。

LongAdder 和 DoubleAdder

  1. LongAdder:适用于 long 类型的累加操作,提供了高效的累加功能,尤其是在多线程环境中。
  2. DoubleAdder:适用于 double 类型的累加操作,同样优化了在高并发环境下的性能。

核心特点

  • 高效性:在多线程环境中,通过减少竞争和锁的使用来提高性能。它们通过内部维护多个计数器(桶)来分摊并发操作的压力,从而减少争用。
  • 线程安全:提供了原子性保证,避免了并发访问中的数据不一致问题。

扩展知识

LongAdderDoubleAdder 的工作原理

  • LongAdderDoubleAdder 通过维护多个 Cell 实例(每个 Cell 实际上是一个 AtomicLongAtomicDouble)来实现并发累加操作。每个线程会选择不同的 Cell 来更新,这样可以减少锁的竞争。
  • 在读取总数时,LongAdderDoubleAdder 会将所有 Cell 的值相加得到最终结果。

AtomicLong 的对比

  • AtomicLong 使用单一的原子变量来实现累加,在高并发情况下,可能会出现大量的竞争和锁争用,导致性能瓶颈。
  • LongAdder 通过分散计数和减少争用来提高性能,特别是在计数器的更新频繁且读操作远多于写操作的情况下。

使用示例

**使用 LongAdder**:

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.concurrent.atomic.LongAdder;

public class LongAdderExample {
private LongAdder counter = new LongAdder();

public void increment() {
counter.increment(); // 原子性自增
}

public long getCount() {
return counter.sum(); // 获取总计数
}
}

**使用 DoubleAdder**:

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.concurrent.atomic.DoubleAdder;

public class DoubleAdderExample {
private DoubleAdder adder = new DoubleAdder();

public void add(double value) {
adder.add(value); // 原子性加法
}

public double getSum() {
return adder.sum(); // 获取总和
}
}
Comments