Как работает "сравнить и установить" в 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. поток 1 вызывает get и получает значение 1.
  2. поток 1, то вычисляется next на 2.
  3. Thread 2 calls get и получает значение 1.
  4. поток 2 вычисляет next на 2.
  5. оба потока пытаются записать значение.

теперь из-за Атомикс - только один поток будет успешным, другой получит false С compareAndSet и снова вокруг.

если бы этот механизм не использовался, было бы вполне возможно, что оба потока увеличат значение, в результате чего фактически будет сделано только одно увеличение.

запутанная бесконечная петля for(;;) будет только действительно цикл, если многие потоки пишут в переменную одновременно. Под очень тяжелой нагрузкой она может сделать петлю вокруг несколько времен но она должно завершиться довольно быстро.


for (;;) является бесконечным циклом, поэтому он просто повторит попытку.