LongAdder
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 #
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
AtomicLongfor statistics gathering. - ConcurrentHashMap Counters: Initializing
LongAdderviacomputeIfAbsentfor 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
AtomicLongwhen 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”) becausesum()only provides a snapshot of the total.