counter++ is actually three operations: load, increment, store. Two threads can read
the same value, both increment, both store — losing one update.
Real CPUs reorder reads/writes; the bug is worse than the simple model suggests. Atomic ops (CAS, atomic increment) preserve the happens-before relationship. Locks work but are slower.