Как работает "сравнить и установить" в AtomicInteger
AtomicInteger работает с двумя понятиями: CAS и volatile переменной.
используя volatile переменная гарантирует, что текущее значение будет видно всем потокам и не будет кэшироваться.
но я смущен концепцией CAS(compare AND set), которая объясняется ниже:
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
мой вопрос в том, чтоif(compareAndSet(current, next) возвращает false? Значение не будет обновляться?
В этом случае что произойдет, когда поток выполняет следующее дело:
private AtomicInteger count = new AtomicInteger();
count.incrementAndGet();
2 ответов
атомные объекты используют сравнить и поменять механизм, чтобы сделать их атомно - т. е. можно гарантировать, что значение был как указано и теперь при новом значении.
код, который вы опубликовали, постоянно пытается установить текущее значение на один больше, чем раньше. Помните, что другой поток также мог выполнить get и пытается установить его. Если два потока соревнуются друг с другом, чтобы изменить значение возможно, один из приращений потерпит неудачу.
рассмотрим следующий сценарий:
- поток 1 вызывает
getи получает значение1. - поток 1, то вычисляется
nextна2. - Thread 2 calls
getи получает значение1. - поток 2 вычисляет
nextна2. - оба потока пытаются записать значение.
теперь из-за Атомикс - только один поток будет успешным, другой получит false С compareAndSet и снова вокруг.
если бы этот механизм не использовался, было бы вполне возможно, что оба потока увеличат значение, в результате чего фактически будет сделано только одно увеличение.
запутанная бесконечная петля for(;;) будет только действительно цикл, если многие потоки пишут в переменную одновременно. Под очень тяжелой нагрузкой она может сделать петлю вокруг несколько времен но она должно завершиться довольно быстро.