Как работает "сравнить и установить" в 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(;;)
будет только действительно цикл, если многие потоки пишут в переменную одновременно. Под очень тяжелой нагрузкой она может сделать петлю вокруг несколько времен но она должно завершиться довольно быстро.