LongAccumulator combines submitted long values with a supplied associative function. A max accumulator records an observed high-water mark under concurrent updates.
Java LongAccumulator: track a concurrent high-water mark
Operational contract
The function Long::max has Long.MIN_VALUE as its identity, so an untouched accumulator is distinguishable from a recorded zero. The sample rejects negative queue depths and returns zero before any sample. get is a metric read, not a coordination signal or a transaction with the queue whose depth was measured. Use an atomic variable when one exact compare-and-set result controls a state transition. Resetting an accumulator while writers run is a separate interval policy and can lose a clean boundary between reporting periods.
Failure case
Forty-seven workers sample backlog depth while shipments arrive. The maximum sample is useful for capacity monitoring. It does not prove the queue never briefly exceeded that value between samples, nor does it freeze the current queue length.
Java code
import java.util.concurrent.atomic.LongAccumulator;
public class BacklogHighWaterMark {
private final LongAccumulator maximum =
new LongAccumulator(Long::max, Long.MIN_VALUE);
public void observe(long pendingShipments) {
if (pendingShipments < 0) throw new IllegalArgumentException("Negative backlog");
maximum.accumulate(pendingShipments);
}
public long highestObserved() {
long observed = maximum.get();
return observed == Long.MIN_VALUE ? 0 : observed;
}
}Performance and ownership cost
A single update has expected low overhead, but contention can cause internal cells and extra O(T) metric-read work for T cells. Space can grow with contention. The max reduction is associative; a side-effecting or order-dependent function would not fit this design.
Common Mistakes
- Do not use a metric read as an exact queue-state invariant.
- Do not reset while writers run without a period boundary.
- Do not choose a nonassociative or side-effecting accumulation function.
Connected lessons
- Java LongAdder: striped counters and the limits of sum snapshots
- Java atomic variables: compare-and-set and one-variable invariants
- Java ConcurrentLinkedQueue: size is not an admission limit
- Java ThreadLocal: restore request context when a pooled thread is reused
- Java LockSupport: park only inside a checked condition loop
- Java concurrent state and handoff quiz
- Advanced Java
