The Java memory model question 22 of 180 junior
Two threads increment a shared int a million times each with no synchronisation. What is the final value and why?
- Exactly 2,000,000
- Correct: Somewhere between 2 and 2,000,000, because
i++is read, add and write, and updates are lost when they interleave - Always exactly 1,000,000
- A
ConcurrentModificationException
i++ compiles to getfield, iadd, putfield. Two threads reading 41, both adding one and both
writing 42 lose an increment. Run it and you will typically get something like 1.3 million, and the
number changes every run.
Interviewers usually follow up with "what is the theoretical minimum?" The answer is 2, not 1. Thread A reads 0 and is descheduled. B runs all but its last increment. A writes 1. B reads that 1 for its last increment and is descheduled. A runs the rest of its loop. B writes 2, last. It cannot go lower, because each thread's own writes happen-before its later reads, so its final read can never see the initial 0.
Three fixes with different costs: synchronized (correct, contended, about 18 ops/us at 8 threads),
AtomicInteger (a CAS loop, about 115), LongAdder (striped cells, about 1256, at the cost of a
sum() that walks them all).