В чем разница между использованием летучего примитива над атомными переменными?

Возможный дубликат:
Java: volatile boolean vs AtomicBoolean

Когда целесообразно использовать примитив volatile (например, boolean, integer или long) вместо AtomicBoolean, AtomicInteger или AtomicLong и наоборот?

Ответы

Ответ 1

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

Например:

if (volatileBoolean) {
    volatileBoolean = !volatileBoolean;
}

может создавать проблемы в многопоточной среде, поскольку переменная может меняться между двумя строками. Если вам нужно, чтобы тест & назначение был атомарным, вы можете использовать:

atomicBoolean.compareAndSet(true, false);

Ответ 2

Использование простой volatile проще и эффективнее, если все, что вы хотите сделать, установлено или получает значение. (Но не получите & установите значение)

Если вам нужно больше операций, таких как getAndIncrement или compareAndSwap, вам нужно использовать классы AtomicXxxx.

Ответ 3

Мы начали запрещать использование volatile в наших источниках, потому что очень легко писать код, который не всегда работает так, как ожидалось.

По моему опыту, люди добавляют volatile для совместного использования значения между потоками. И тогда кто-то еще начинает изменять значение. И большую часть времени это работает. Но в производстве вы начинаете получать нечетные ошибки, которые действительно трудно отследить. Счетчики увеличиваются в 100 000 раз (тесты только увеличивают их в 10 раз), но заканчиваются на 99'997. В Java 1.4 длинные значения могут быть повреждены действительно, очень редко.

Классы-помощники Atomic*, с другой стороны, налагают только небольшие накладные расходы, и они всегда работают как рекламируемые.

Поэтому, если у вас есть очень хорошая причина (*) использовать volatile, всегда предпочитайте вспомогательные классы Atomic*.

Если вы точно не знаете, что делает каждый символ в классах помощника Atomic*, тогда вам действительно следует избегать volatile.

*: преждевременная оптимизация никогда не является веской причиной.

Ответ 4

В классах Atomic* выполняется перенос примитива volatile того же типа. Из источника:

public class AtomicLong extends Number implements java.io.Serializable {
   ...
   private volatile long value;
   ...
   public final long get() {
       return value;
   }
   ...
   public final void set(long newValue) {
       value = newValue;
   }

Итак.

Когда целесообразно использовать летучий примитив (например, логический, целочисленный или длинный) вместо AtomicBoolean, AtomicInteger или AtomicLong

Если все, что вы делаете, это получение и установка Atomic*, тогда вы можете просто иметь поле volatile.

... и наоборот?

Тем не менее, существуют классы Atomic*, которые представляют собой более сложные функции, такие как incrementAndGet(), compareAndSet() и другие, которые реализуют несколько операций (get/increment/set, test/set) без блокировки. Вот почему классы Atomic* настолько мощные.

Также важно отметить, что упаковка поля volatile с использованием класса Atomic* - хороший способ инкапсулировать критически важный общий ресурс с точки зрения объекта. Это означает, что разработчики не могут просто иметь дело с полем, предполагая, что он не разделен, возможно, вставляя проблемы с помощью field++; или другого кода, который вводит условия гонки.