Можно ли избежать энергозависимого чтения в двойной проверке блокировки после инициализации, как это? - PullRequest
2 голосов
/ 20 ноября 2011

Используя логическое значение volatile, которое доступно только для чтения, если экземпляр имеет значение null, могу ли я избежать частого энергозависимого чтения по умолчанию после инициализации экземпляра, как это происходит?Никто не видел, чтобы кто-то рекомендовал двойную проверку блокировки, как это, но, похоже, избегает нестабильного чтения после полной инициализации ...

public class Singleton {

   private static volatile boolean initialized = false;
   private static Object lock = new Object();
   private static Singleton instance;

      public static Singleton getInstance(){
           if(instance != null) return instance;
           if(!initialized){
                synchronized(lock){
                   if(!initialized){
                       instance = new Singleton();
                       initialized = true;
                   }
                }
           }
           return instance;

       }

}

Ответы [ 4 ]

5 голосов
/ 20 ноября 2011

Нет, вы не можете. Если поток A достиг синхронизированного блока и выполняет

instance = new Singleton();
В строке

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

См. Статью DLCP для вариантов и объяснений этого шаблона.

1 голос
/ 20 ноября 2011

Ваша попытка оптимизации не только преждевременна, но и бесполезна, цитируя Является ли изменяемая переменная 'читает' так же быстро, как и обычное чтение? :

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

0 голосов
/ 21 ноября 2011

volatile чтение (почти) бесплатно на большинстве аппаратных средств, volatile запись стоит дорого, хотя ... Так зачем беспокоиться?

Короткий ответ - нет. между instance = new Singleton() и initialized = true на слабой модели памяти, где можно переупорядочить хранилища, читатель может увидеть неинициализированный Signleton. на x86 и sparc TSO нет переупорядочения магазина-магазина, но на ARM и IA64 это происходит.

0 голосов
/ 21 ноября 2011

Если вы хотите ленивого создания экземпляров, но беспокоитесь о производительности, используйте подход «внутреннего класса» - он чище и короче (и чуть-чуть более эффективен). Примерно так:

public class Singleton {

    private static class SingletonHolder {
        private static final Singleton instance = new Singleton();
    }

    public static Singleton getInstance(){
        return SingletonHolder.instance;
    }

}

Хитрость в том, что экземпляр создается во время инициализации внутреннего класса - это произойдет при первом обращении к классу, при первом вызове getInstance(). Кстати, избегайте таких «статичных» синглетонов, если только для этого нет веских причин.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...