AtomicInteger uses compare-and-swap (CAS) processor instruction to update the counter. It works great, until under high contention it doesn’t run into a spin lock, as the operation is retried in infinite loop, until it succeeds.
Java8 LongAdder does not try to compete for accessing the value to increment, but instead – saves the value in different places in the memory (check out the Java source code for details). So concurrent saves can be performed at one time. When the read operation is called – summing is performed over all of these places.
This is great for writing performance, slightly less great for reading and precision. In negative scenario, increment(), increment() and sum() can return 0 or 1 (if the increment operations are performed after summing is started). The value will be correct in the end, but momentarily value can be wrong. Which is fine, for coarse-grained operations as for example collecting statistics. Not so fine for… fine computations.
