LongAdder distributes concurrent additions across internal counters and combines their values when sum is requested.
Java LongAdder: striped counters and the limits of sum snapshots
This program targets Java 8 without preview flags. Use a full JDK for compiler-based examples.
Count observations, not remaining capacity
A parser can record how many rows workers accepted. Several workers increment the same metric, then the coordinator joins all workers and reports the count. A striped counter fits an observation metric because callers do not need to claim the next unique value or atomically reject a quota overrun.
The program waits until every writer has ended before reading the total. During concurrent updates, sum does not promise an atomic snapshot. Using it in a check-then-increment admission rule can allow more callers than the permitted capacity. An atomic transition or a semaphore is a different contract.
Reset needs an ownership rule
sumThenReset is useful only when a non-atomic reset is acceptable under the application timing rule. It is not a substitute for a precisely bounded reporting interval with active writers. Resetting a live metric and publishing it as an exact count can lose the connection between requests and windows.
The runtime chooses its internal stripe arrangement. This fixture proves the final arithmetic result after joins, not a throughput improvement over AtomicLong on every machine. False sharing, contention, processor count and read frequency all affect a real comparison.
Working program
import java.util.concurrent.atomic.LongAdder;
public class AcceptedRowMetric {
public static void main(String[] args) throws Exception {
LongAdder accepted = new LongAdder();
Thread[] writers = new Thread[4];
for (int index=0; index<writers.length; index++) {
writers[index] = new Thread(() -> { for (int row=0; row<750; row++) accepted.increment(); });
writers[index].start();
}
for (Thread writer : writers) writer.join();
System.out.println(accepted.sum());
System.out.println(accepted.sumThenReset());
System.out.println(accepted.sum());
}
}Output
3000
3000
0Costs and boundaries
Each increment performs bounded counter work but its contention cost is runtime-dependent. sum visits internal counter state and may cost more than reading one AtomicLong. This fixture retains four worker threads and one counter. It does not publish a timing comparison or justify replacing every application counter with LongAdder.
Common Mistakes
- Do not use sum as an atomic quota decision while writers are active.
- Do not assume reset creates an exact reporting window under concurrent updates.
- The final count requires completion of all writers before observation.
Read next
Atomic transitions, Admission permits, Measured comparisons.
