Операции AtomicInteger и Compare

Я пытаюсь использовать переменную AtomicInteger в качестве блокировки. Итак, интересно, является ли код, размещенный ниже, потокобезопасным. Я знаю, что incrementAndGet() — атомарная операция. Но я не уверен, что последующая операция '==' также будет атомарной (что, если значение увеличится до 2 к тому времени, когда я сделаю сравнение). Итак, публикуя этот вопрос, чтобы услышать ваши мысли.

private AtomicInteger count = new AtomicInteger(0); //Shared variable
private final int max = 1;

if(count.incrementAndGet() == max) {
  //Do something
}

person V1666    schedule 20.09.2018    source источник
comment
Тем не менее, вы заново изобретаете Semaphore.   -  person chrylis -cautiouslyoptimistic-    schedule 21.09.2018


Ответы (1)


Поскольку incrementAndGet() является атомарной операцией, максимум один поток получит 1 в качестве результата (пока для AtomicInteger не задано значение меньше 1). Это гарантируется AtomicInteger. Хотя фактическое сравнение не является частью этой атомарной операции, только поток, получивший 1, попадет в блок if. Это потому, что при сравнении сравниваются два значения типа int: результат incrementAndGet()) и max. AtomicInteger не играет в этом роли, поскольку примитив int не меняет своего значения при изменении внутреннего состояния count. tl;dr: Ваш код эквивалентен:

final int val = count.incrementAndGet(); // (it makes no difference if val is not 'final`)
if (val == max) {
    // ...
}

Java предоставляет множество других способов обеспечения безопасности потоков (Блокировка, CountDownLatch, Семафор , ...), но поскольку вы имеете в виду AtomicInteger, я считаю, что AtomicInteger.compareAndSet() более точно соответствует тому, что вы просили:

if (count.compareAndSet(0, 1)) {
    // executed if count == 0
    count.set(0);
}
person steffen    schedule 20.09.2018
comment
Теперь намного понятнее. Я хочу, чтобы только один поток выполнял некоторые функции. Поэтому я проверяю счет. Поскольку гарантируется, что только один поток увидит значение 1, я могу с уверенностью ожидать, что логика, находящаяся в условии «если», будет потокобезопасной. Поскольку каждая операция incrementandGet() будет увеличивать счетчик, будет только один поток, читающий значение 1. Итак, это отвечает на мой вопрос. Спасибо, Стефен. - person V1666; 21.09.2018