Возможный дубликат:
Java: volatile boolean vs AtomicBoolean
Когда целесообразно использовать примитив volatile (например, boolean, integer или long) вместо AtomicBoolean, AtomicInteger или AtomicLong и наоборот?
Возможный дубликат:
Java: volatile boolean vs AtomicBoolean
Когда целесообразно использовать примитив volatile (например, boolean, integer или long) вместо AtomicBoolean, AtomicInteger или AtomicLong и наоборот?
Семантика видимости точно такая же, ситуация, когда использование атомных примитивов полезна, - это когда вам нужно использовать свои атомные методы.
Например:
if (volatileBoolean) {
volatileBoolean = !volatileBoolean;
}
может создавать проблемы в многопоточной среде, поскольку переменная может меняться между двумя строками. Если вам нужно, чтобы тест & назначение был атомарным, вы можете использовать:
atomicBoolean.compareAndSet(true, false);
Использование простой volatile проще и эффективнее, если все, что вы хотите сделать, установлено или получает значение. (Но не получите & установите значение)
Если вам нужно больше операций, таких как getAndIncrement или compareAndSwap, вам нужно использовать классы AtomicXxxx.
Мы начали запрещать использование volatile в наших источниках, потому что очень легко писать код, который не всегда работает так, как ожидалось.
По моему опыту, люди добавляют volatile для совместного использования значения между потоками. И тогда кто-то еще начинает изменять значение. И большую часть времени это работает. Но в производстве вы начинаете получать нечетные ошибки, которые действительно трудно отследить. Счетчики увеличиваются в 100 000 раз (тесты только увеличивают их в 10 раз), но заканчиваются на 99'997. В Java 1.4 длинные значения могут быть повреждены действительно, очень редко.
Классы-помощники Atomic*, с другой стороны, налагают только небольшие накладные расходы, и они всегда работают как рекламируемые.
Поэтому, если у вас есть очень хорошая причина (*) использовать volatile, всегда предпочитайте вспомогательные классы Atomic*.
Если вы точно не знаете, что делает каждый символ в классах помощника Atomic*, тогда вам действительно следует избегать volatile.
*: преждевременная оптимизация никогда не является веской причиной.
В классах 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++; или другого кода, который вводит условия гонки.