返回

Java并发之原子操作类18罗汉神通倍增-LongAdder解读

后端

LongAdder:Java并发编程中的神兵利器

什么是原子操作?

在多线程编程中,原子操作指的是在多线程环境下对共享资源进行安全且一致的访问。Java并发包提供了丰富的原子操作类,其中AtomicLong、AtomicInteger等基本类型原子类广为人知。

原子操作类的局限性

然而,随着并发场景的复杂化,基本类型原子操作类也暴露了一些局限性:

  • 性能瓶颈: 基本类型原子类采用锁机制保证原子性,当并发量较大时,锁竞争会成为性能瓶颈。
  • 拓展性差: 基本类型原子类仅支持基本数据类型,对于复杂对象或引用类型,无法提供原子操作支持。
  • 功能单一: 基本类型原子类只能实现简单的原子增减或更新操作,对于更复杂的原子操作需求,难以满足。

LongAdder:原子操作的革命

为了解决这些局限,Java并发包引入了原子操作增强类,其中LongAdder是引用类型原子类的杰出代表。LongAdder通过分段锁机制和可扩展性设计,极大地提高了并发性能和适应性。

分段锁机制

LongAdder将Long值拆分成多个片段(segment),每个片段使用独立的锁进行保护。这种分段锁机制有效降低了锁竞争,从而提升了并发性能。

可扩展性

LongAdder可以自动扩容片段数量,适应并发量的变化。当片段数量超过阈值时,LongAdder会创建新的片段并重新分配数据,确保高并发场景下的稳定运行。

支持复杂原子操作

除了基本的增减操作,LongAdder还支持更复杂的原子操作,如:

  • 累加数组元素
  • 获取最大值或最小值
  • 统计非负整数出现的次数

LongAdder的应用场景

LongAdder广泛应用于需要高并发且低延迟的场景,如:

  • 计数器
  • 统计信息收集
  • 并行归约

LongAdder的源码解析

核心成员变量

  • cells:分段数组,存储Long值。
  • threshold:分段数量的阈值,当超过阈值时,LongAdder会自动扩容。

构造方法

public LongAdder() {
    this(Runtime.getRuntime().availableProcessors());
}

默认构造方法根据CPU核数创建分段数组。

increment操作

public void increment() {
    Cell[] as = cells;
    int m = (int) (getProbe() & (as.length - 1));
    Cell a;
    while ((a = as[m]) == null) {
        Cell r = new Cell(0L, null);
        if (a == null) {
            as[m] = r;
            break;
        }
        if (m == 0) {
            threshold = Math.min(as.length * 2, MAXIMUM_CELLS);
            Cell[] as2 = new Cell[threshold];
            System.arraycopy(as, 0, as2, 0, as.length);
            cells = as2;
            as = as2;
        }
    }
    a.value += 1L;
}

increment操作通过分段锁机制,尝试获取分段并累加Long值。如果分段不存在,则创建新分段并竞态设置。当分段数量超过阈值时,LongAdder会扩容分段数组。

decrement操作

public void decrement() {
    Cell[] as = cells;
    int m = (int) (getProbe() & (as.length - 1));
    Cell a;
    while ((a = as[m]) == null) {
        Cell r = new Cell(0L, null);
        if (a == null) {
            as[m] = r;
            break;
        }
        if (m == 0) {
            threshold = Math.min(as.length * 2, MAXIMUM_CELLS);
            Cell[] as2 = new Cell[threshold];
            System.arraycopy(as, 0, as2, 0, as.length);
            cells = as2;
            as = as2;
        }
    }
    a.value -= 1L;
}

decrement操作与increment操作类似,但进行的是减法操作。

结论

LongAdder通过分段锁机制和可扩展性设计,极大地提升了并发性能和适应性。其源码解析展示了其内部实现的精巧与高效,为并发编程提供了强大的工具。掌握LongAdder的使用技巧,将助你