Шаг не атомарный. Он читает значение, затем записывает увеличенное значение. Между этими двумя операциями другой поток может взаимодействовать с суммой сложным образом.
Диапазон значений на самом деле не от 100 до 200. Этот диапазон основан на неверном предположении, что потоки либо сменяются, либо выполняют каждое чтение одновременно. Есть еще много возможных перемежений, некоторые из которых дают заметно разные значения. Наихудший случай выглядит следующим образом (x
представляет неявное временное выражение, используемое в выражении sum++
):
Thread A Thread B
---------------- ----------------
x ← sum (0)
x ← sum (0)
x + 1 → sum (1)
x ← sum (1)
x + 1 → sum (2)
⋮
x ← sum (98)
x + 1 → sum (99)
x + 1 → sum (1)
x ← sum (1)
x ← sum (1)
x + 1 → sum (2)
⋮
x ← sum (99)
x + 1 → sum (100)
x + 1 → sum (2)
Таким образом, наименьшее возможное значение равно 2. Проще говоря, два потока отменяют тяжелую работу друг друга. Вы не можете опуститься ниже 2, потому что поток B не может подать ноль в поток A - он может только вывести увеличенное значение - и поток A должен, в свою очередь, увеличить значение 1, которое ему дал поток B.