Зачем использовать волатильный с синхронизированным блоком?

StackOverflow https://stackoverflow.com//questions/9665483

Вопрос

Я видел некоторые примеры в Java, где они делают синхронизацию на блоке кода, чтобы изменить некоторую переменную, в то время как эта переменная была объявлена летучим изначально.Сихронизированный блок, который инициализирует этот экземпляр ... Мой вопрос в том, почему мы объявляем его волатильным, пока мы синхронизируем на нем, почему нам нужно сделать обоими ??Разве один из них недостаточно для другого ??

public class someClass {
volatile static uniqueInstance = null;

public static someClass getInstance() {
        if(uniqueInstance == null) {
            synchronized(someClass.class) {
                if(uniqueInstance == null) {
                    uniqueInstance = new someClass();
                }
            }
        }
        return uniqueInstance;
    }
.

Спасибо заранее.

Это было полезно?

Решение

Синхронизация само по себе будет достаточно в этом случае, если первая проверка была в синхронизированном блоке (но это не так, и один поток не может видеть изменения, выполненные другим, если переменная не была волатильной).Нестабильный один не будет достаточно, потому что вам нужно выполнить более одной операции атомным образом.Но остерегайтесь!То, что у вас здесь, так называемая двойная проверка - обычная идиома, к сожалению, не работает надежно .Я думаю, что это изменилось с момента Java 1.6, но все же такой код может быть рискованным.

Редактировать : Когда переменная летучих, этот код правильно работает, поскольку JDK 5 (не 6, как я писал ранее), но он не будет работать, как ожидалось в соответствии с JDK 1.4 или ранее.

Другие советы

Это использует двойную проверку заблокировки, обратите внимание, что if(uniqueInstance == null) не находится в синхронизированной части.

Если uniqueInstance не является летучим, он может быть «инициализирован» с частично построенным объектом, в котором части его не видны, кроме потока, выполняемого в блоке synchronized.Волатиль делает это все или ничего не работает в этом случае.

Если у вас не было синхронизированного блока, вы можете в конечном итоге с двумя потоками, получающимися в этот момент одновременно.

if(uniqueInstance == null) {
      uniqueInstance = new someClass(); <---- here
.

и вы строите 2 объекта Someclass, который поражает цель.

Строго говоря, вам не нужен волатильный, метод мог быть

public static someClass getInstance() {
    synchronized(FullDictionary.class) {
         if(uniqueInstance == null) {
             uniqueInstance = new someClass();
          }
         return uniqueInstance;
    }
}
.

Но это вставляет синхронизацию и сериализацию каждого потока, которая выполняет getInstance ().

Это сообщение объясняет идеюза волатильным.

Он также обращается в семанную работу, Java Consullence на практике ,

Основная идея заключается в том, что параллелизм не только включает в себя защиту общего состояния, но и на видимость этого состояния между потоками: именно здесь воет волатильный. (Этот больший договор определяется модель памяти Java .)

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

Мои два цента здесь

Фрист Быстрое объяснение интуиции этого кода

if(uniqueInstance == null) {
        synchronized(someClass.class) {
            if(uniqueInstance == null) {
                uniqueInstance = new someClass();
            }
        }
    }
.

Причина, по которой она проверяет UniqueinStance== NULL дважды, - снизить накладные расходы на вызов синхронизированного блока, который относительно медленнее.Так называется двойной проверкой.

Во-вторых, причина, по которой она использует синхронизированную, легко понять, он делает две операции внутри синхронизированного блока атомной связи.

Последний летучий модификатор гарантирует, что все темы видят одну и ту же копию, поэтому самая первая проверка за пределами синхронизированного блока увидит значение UnaliveStance таким образом, что «синхронизировано» с синхронизированным блоком.Без летучих модификатора один нить может назначить значение для UnaliveNStance, но другой поток может не увидеть его по первой проверке.(Хотя второй чек увидит это)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top