LongAdder and striped counters
Why one hot AtomicLong stops scaling, how LongAdder stripes a counter across padded cells, what false sharing and @Contended are, why sum() is not a snapshot, and when AtomicLong is still the right pick.
On this page
- Picture it first: one till or many
- Why one hot AtomicLong becomes a bottleneck
- Under the hood: AtomicLong vs LongAdder on a real laptop
- How LongAdder works: Striped64 in plain words
- LongAccumulator: the same trick for max, min and friends
- Let's build it: count requests per second across 64 threads
- When AtomicLong is still the right pick
- Real world
- Advanced: false sharing, @Contended and the price of cells
- How to say it in the interview
🧮 What is LongAdder (and what is a striped counter)?
A striped counter splits one hot number into several smaller ones so that threads stop fighting over a single spot in memory, then adds the pieces together when someone asks for the total. java.util.concurrent.atomic.LongAdder (Java 8+) is the JDK's built-in version: increment() lands on one of a handful of padded cells, and sum() adds them all up. On my 14-core laptop, 8 threads doing 16 million increments took about 550 ms on an AtomicLong and about 10 ms on a LongAdder.
For this lesson, we'll start with a question that sounds silly: why would adding 1 to a number ever be slow? Then we'll see what a hot AtomicLong does to your CPU, fix it the way supermarkets fixed checkout queues, and open up LongAdder to see the base field, the cell table, the per-thread hash and the @Contended padding that make it work. Interviewers like this topic because it's where "I know AtomicLong is thread-safe" turns into "I know what thread-safe costs", and that's the line between mid-level and senior answers.
What you’ll learn
- Explain why a hot
AtomicLongstops scaling: every core fights over one cache line, and failed CAS attempts retry - Describe the striping idea: split one number into many, add them up only when someone asks
- Walk through
LongAdderinternals: thebasefield, the lazily createdCell[], the per-thread probe and growth up to about the number of CPUs - Explain false sharing in plain words and how
@Contendedpadding prevents it - Know that
sum()is not an atomic snapshot and whatsumThenReset()does - Use
LongAccumulatorfor max, min or custom functions that are associative and commutative - Choose between
AtomicLongandLongAdderin one sentence, and design a counter for a hot path
Premium lesson
Keep reading with the Java Pass
The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.
- Picture it first: one till or many
- Why one hot AtomicLong becomes a bottleneck
- Under the hood: AtomicLong vs LongAdder on a real laptop
- How LongAdder works: Striped64 in plain words
- LongAccumulator: the same trick for max, min and friends
- Let's build it: count requests per second across 64 threads
- When AtomicLong is still the right pick
- Real world
- Advanced: false sharing, @Contended and the price of cells
- How to say it in the interview
From ₹299 · one-time payment · No auto-renewal
Further reading (12)
- LongAdder (Java SE 21 API): preferable to AtomicLong under high contention for statistics; sum() is not an atomic snapshot
- LongAccumulator (Java SE 21 API): the function must be side-effect-free; order of accumulation is not guaranteed
- AtomicLong (Java SE 21 API): single-value atomic with compareAndSet and exact reads
- OpenJDK jdk21u source: Striped64.java: base, Cell[] table, @Contended cells, probe-based hashing, growth bounded by NCPU
- OpenJDK jdk21u source: LongAdder.java: add() fast path on base, fallback to cells; sum() walks the table
- OpenJDK jdk21u source: ConcurrentHashMap.java: baseCount plus CounterCell[] keeps size() cheap, the same striping idea
- JEP 142: Reduce Cache Contention on Specified Fields: @Contended padding against false sharing
- Martin Thompson: False Sharing: false sharing explained with measurements
- Aleksey Shipilev: JVM Anatomy Quarks: how HotSpot lays out and pads fields
- Dropwizard Metrics: Counter.java: production counters backed by LongAdder
- Micrometer: CumulativeCounter.java: counter backed by DoubleAdder
- Java Concurrency in Practice (Goetz et al.), chapter 15: atomic variables and non-blocking synchronization