Представьте себе counter
равно 9.
Тема 1 делает это:
counter++; // counter = 10
Тема 2 делает это:
counter++; // counter = 11
if(counter==10) // oops
Теперь вы можете подумать, что можете это исправить с помощью:
if(counter >= 10) counter -= 10;
Но теперь, что произойдет, если оба потока проверит условие и обнаружит, что оно истинно, тогда оба потока уменьшат счетчик на 10 (теперь ваш счетчик отрицателен).
Или на еще более низком уровне, counter++
- это на самом деле три операции:
- Получить
counter
- Добавить один к
counter
- Магазин
counter
Итак:
- поток 1 получает счетчик
- поток 2 получает счетчик
- Оба потока добавляют один к своему счетчику
- Оба потока хранят свой счетчик
В этой ситуации вы хотели, чтобы счетчик увеличивался вдвое, но он увеличивается только один раз. Вы можете представить это так, как будто этот код выполняется:
c1 = counter;
c2 = counter;
c1 = c1 + 1;
c2 = c2 + 1;
counter = c1; // Note that this has no effect since the next statement overrides it
counter = c2;
Таким образом, вы можете обернуть его в блок synchronized
, но лучше использовать AtomicInteger , если у вас всего несколько потоков:
public class counting {
private static AtomicInteger counter = new AtomicInteger(0);
public static void counterCheck() {
int value = counter.incrementAndGet();
// Note: This could loop for a very long time if there's a lot of threads
while(value >= 10 && !counter.compareAndSet(value, value - 10)) {
value = counter.get();
}
}
}