Когда предпочтительнее использовать volatile boolean в Java, а не AtomicBoolean? - PullRequest
53 голосов
/ 02 февраля 2011

Я посмотрел на другие нестабильные вопросы против Atomicxxxx в SO (включая этот ) и прочитал описание java.util.current.atomic , и я не совсем доволен нюансами.

Если я пытаюсь выбрать между использованием volatile boolean и AtomicBoolean, существуют ли практические различия, кроме атомарных операций чтения-изменения-записи, предлагаемых AtomicBoolean? (например, compareAndSet() и getAndSet())

Предположим, у меня есть

volatile boolean flag;

Затем один или несколько потоков устанавливают флаг (но не сбрасывают его). Если у меня есть один поток, который читает флаг, и если установлен, выполняет действие, а затем очищает флаг, является ли volatile адекватным?

Есть ли более высокая стоимость для AtomicBoolean, чем для volatile boolean, с точки зрения

  • пространство памяти
  • снижение производительности (volatile boolean, кажется, требует ограждения памяти, AtomicBoolean, кажется, требует ограждения памяти + некоторая незначительная блокировка операций CAS согласно описанию java.util.current.atomic)

Мой инстинктивный вызов - просто пойти с AtomicBoolean и быть в безопасности, но я хочу понять, есть ли когда-нибудь ситуация для использования volatile boolean (например, если у меня их было тысячи экземпляров, и производительность была проблемой).

Ответы [ 5 ]

70 голосов
/ 02 февраля 2011

Основное отличие между AtomicBoolean и volatile с практической точки зрения состоит в том, что операция сравнения и задания не является атомарной с volatile переменными.

 volatile boolean b;

 void foo() {
   if( b ) {
     //Here another thread might have already changed the value of b to false
     b = false;
   }
 }

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

19 голосов
/ 03 февраля 2011

Я не уверен, что полностью согласен с другими ответами здесь;Ответ biziclop верен, но я не уверен, что мы можем сделать вывод, что вы в безопасности, если не будем знать больше подробностей.

В простом случае чередование может выглядеть так:

Thread 1 (writer)   Thread 2 (Writer)  Thread 3 (Reader)
-----------------   -----------------  -----------------
flag = true;
                                       if (flag) {
                    flag = true;
                                         flag = false;
                                         doStuff();

, и это может быть хорошо (второй набор от flag до true не имеет значения, так как doStuff() все еще, вероятно, будет видеть все, что нужно потоку 2.

Однако есливы изменяете порядок, в котором поток 3 выполняет:

Thread 1 (writer)   Thread 2 (Writer)  Thread 3 (Reader)
-----------------   -----------------  -----------------
flag = true;
                                       if (flag) {
                                         doStuff();
                    flag = true;
                                         flag = false;

, тогда обновление потока 2. может быть потеряно.

Конечно, вы должны быть осторожны с тем, что делает поток 2, чтобы убедиться, чтовидим в потоке 3. Если есть другое состояние, которое необходимо установить в потоке 2, порядок также становится важным там.

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

17 голосов
/ 02 февраля 2011

По существу все AtomicBoolean является volatile boolean в объекте.

На каждый объект будут накладываться небольшие накладные расходы. Возможно незначительное, но, возможно, больше памяти, чтобы попасть в кеш.

Если вам нужно использовать AtomicBooleanFieldUpdater, тогда производительность значительно возрастает. Это может быть хорошо, если вы не собираетесь делать это часто (как attach в NIO).

7 голосов
/ 03 октября 2012

Здесь много полезной информации. Однако я бы добавил еще одно отличие, которое может оказаться полезным. Вы можете иметь массив AtomicBooleans, но вы не можете (насколько мне известно) иметь массив летучих логических значений.

2 голосов
/ 02 февраля 2011

Затем один или несколько потоков устанавливают флаг (но не сбрасывают его).Если у меня есть один поток, который читает флаг, и если установлен, выполняет действие, а затем очищает флаг, является ли энергозависимым адекватным?

Да, если вам не нужны специальные способности AtomicBoolean, это прекрасно, чтобы использовать volatile для этого.Фактически, это одно из немногих разумных применений для volatile.

...