Skip to main content
  1. Java Concurrency (java.util.concurrent)/

LongAdder

2 mins

LongAdder is a specialized atomic variable designed for high-contention scenarios. It is part of the Striped64 family of classes in the java.util.concurrent.atomic package.

Source Code #

View Source on GitHub

Mechanism: The “Striped64” Algorithm #

In a standard AtomicLong, all threads compete for the same memory location. Under high contention, most CAS operations fail, leading to significant performance degradation. LongAdder addresses this by using a set of variables that maintain the sum.

public class LongAdder extends Striped64 implements Serializable {
    // Base value, used when no contention
    private volatile long base;

    // Array of cells, used when contention occurs
    private volatile Cell[] cells;

    public void add(long x) {
        Cell[] cs; long b, v; int m; Cell c;
        if ((cs = cells) != null || !casBase(b = base, b + x)) {
            // ... increment an individual cell based on thread hash ...
        }
    }
}

When multiple threads try to update the sum, LongAdder creates an array of “cells” and maps each thread to a specific cell. Each thread updates its own cell, reducing contention. The total sum is only calculated when sum() is called.

Canonical Usage #

When to use: Use LongAdder for accumulators or counters that are updated frequently by many threads (e.g., tracking the total number of requests in a high-traffic web server or collecting performance metrics).

Common Patterns:

  • High-Contention Summing: Replaces AtomicLong for statistics gathering.
  • ConcurrentHashMap Counters: Initializing LongAdder via computeIfAbsent for scalable frequency counting.
LongAdder requests = new LongAdder();

// Fast increment (scales with number of threads)
requests.increment();

// Slower retrieval (requires summing all cells)
long total = requests.sum();

Performance Trade-offs #

  • Pros: Outstanding scalability under high contention. Significantly higher throughput than AtomicLong when many threads are active.
  • Cons: sum() is relatively slow (linear time to sum all cells). It is not suitable for fine-grained synchronization (e.g., “if current sum is 10, then do X”) because sum() only provides a snapshot of the total.