Классический пример: представьте, что у вас есть два потока операций, и оба они ссылаются на один и тот же метод:
public void addToGlobalVar(int y) {
int x = globalVar; //what if a thread stops right after this line?
x += y;
globalVar = y;
}
, где globalVar
- это другое предопределенное число, с которым этот метод может взаимодействовать, изадавать.Допустим, globalVar равен 50.
Потоки вычисляют время вычислений несколько произвольно, поэтому вы никогда не будете полностью знать, какая точная наносекунда останавливается, а другая получает время ЦП.
В этом примере, есливы запустили AsyncTask в дополнение к потоку пользовательского интерфейса, и оба в какой-то момент используют addToGlobalVar(10)
, что может случиться так, что один поток может быть прерван во второй строке этого блока кода.Если другой поток проходит, пока тот спит, он успешно установит globalVar равным 60. Но когда другой пробуждается, он все еще думает, что x = 50, и затем собирается установить его равным 60. Так что, по сути, вы простосделал 50 + 10 + 10 = 60. Надеюсь, вы можете увидеть, как это становится проблемой.
Вы можете исправить этот простой пример, сделав расчет атомарным (пропустите объявление x, 1 строка, все вычисления сделаны) или еслилогику не удалось сжать до 1 строки, вы делаете атомарный блок кода с помощью synchronized
.