Внутренняя синхронизация на том же объекте как внешняя синхронизация

Недавно я посетил лекцию относительно некоторых шаблонов разработки:

Следующий код был отображен:

public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {      //1
      Singleton inst = instance;         //2
      if (inst == null)
      {
        synchronized(Singleton.class) {  //3
          inst = new Singleton();        //4
        }
        instance = inst;                 //5
      }
    }
  }
  return instance;
}

взятый от: перепроверяемая блокировка: Возьмите два

Мой вопрос не имеет никакого отношения к вышеупомянутому шаблону, но с синхронизируемыми блоками:

Есть ли какое-либо преимущество вообще для двойной синхронизации, сделанной в строках 1 и 3 относительно того, что синхронизировать операция сделана на том же Объекте?

6
задан Yaneeve 17 March 2010 в 15:48
поделиться

3 ответа

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

В новом JMM он ничего не делает. Новый JMM указан для 1.5 и реализован для "Sun" 1.4 JRE. 1.5 завершил свой период End of Service Life некоторое время назад, поэтому вам не нужно беспокоиться о старой JMM (ну, возможно, Java ME сделает что-то непредсказуемое).

11
ответ дан 8 December 2019 в 16:01
поделиться

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

Подробности вы найдете в Java Memory Model

2
ответ дан 8 December 2019 в 16:01
поделиться

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

Например,

public void doSomething()
{
  synchronized(this) { // "this" locked
    methodCall1();
    synchronized(this) {
      methodCall2();
    } // memory flushed
    methodCall3();
  } // "this" unlocked and memory flushed
}

Может быть скомпилирован для выполнения в этом порядке

public void doSomething()
{
  synchronized(this) { // "this" locked
    methodCall1();
    synchronized(this) {
      methodCall2();
      methodCall3();
    } // memory flushed
  } // "this" unlocked and memory flushed
}

Для более подробного объяснения ознакомьтесь с Двойная проверка блокировки в Исправление, которое не работает участок примерно на треть пути вниз.

2
ответ дан 8 December 2019 в 16:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: