Нужно ли делать AtomicBoolean еще и volatile? - PullRequest
0 голосов
/ 21 июня 2020

Насколько я понимаю: объявление переменной volatile гарантирует видимость для других потоков при записи в эту переменную. По сути, каждая write в изменчивую переменную происходит до последующего reads.

Я понимаю атомарность AtomicBoolean.compareAndSet() и то, как она обеспечивает атомарность операции read+write, которая volatile нет. Но я не вижу никаких do c, обеспечивающих видимость гарантию AtomicBoolean, например, следующее:

  1. Каждый успешный write на AtomicBoolean.compareAndSet() в конечном итоге будет виден к последующим AtomicBoolean.get() и AtomicBoolean.compareAndSet() другими потоками.

Но я продолжаю видеть код, помеченный как thread-safe, который выглядит следующим образом:

// default false so that first-thread that execute() can enter the logic block
private static final  AtomicBoolean executing = new AtomicBoolean(false);


public void execute() {
    if (executing.compareAndSet(false, true)) {  // check if the executing is previously false and if so update it to true
        try {
            // thead-safe code, i.e only one thread guaranteed to execute at any point of time time
        } finally {
            executing.set(false); // executing thread now re-sets the test value
        }
    }
}

Не должно переменная executing также объявила volatile, например private static volatile AtomicBoolean executing = new AtomicBoolean(false);? Так достигается гарантия видимости, необходимая для AtomicBoolean?

Ответы [ 2 ]

3 голосов
/ 21 июня 2020

Нужно ли делать AtomicBoolean также volatile?

No.

В этом примере executing объявлено как static final, поэтому он будет инициализирован один раз во время инициализации класса и безопасно опубликован для любого другого кода, который в нем нуждается.

Это поведение гарантировано, потому что существует происходит-до между завершением инициализации классов ( обычно) и любое последующее использование любой переменной stati c, объявленной классом. Тот факт, что переменная также final, исключает любые последующие присваивания стату c, которые отрицают происходит-до .

Вам нужно только объявить executing как volatile, если что-то могло присвоить ему новое значение после инициализации. Здесь это невозможно без неприятных размышлений. (И JLS заявляет, что если вы сделаете такие вещи, чтобы изменить final, гарантии модели памяти не применяются.)

Вы получили бы аналогичный эффект, если бы executing было final, но поле экземпляра, а не поле static. Рассуждения немного отличаются, но это также явно упоминается в JLS.

Наконец, синтаксис Java не позволяет комбинировать модификаторы volatile и final. Эта комбинация не имеет смысла.

2 голосов
/ 21 июня 2020

Мы не можем использовать приведенный ниже код

private static volatile final AtomicBoolean executing = new AtomicBoolean(false);

Использование volatile и final вместе недопустимо . Как указано в @ RealSkepti c var, который никогда не изменится (окончательный), не обязательно иметь volatile. Volatile используется для тех переменных, значения которых изменяются во время выполнения одним или несколькими потоками.

// Удачного обучения

...