2014-09-01 5 views
0

Я хочу быть уверенным, что мой экземпляр Singleton доступен безопасно и с минимальной синхронизацией, но у меня есть сомнение относительно предложения first if вне синхронизированного блока. Возможно ли, чтобы INSTANCE имел непустое значение, когда оно не было полностью построено? Если да, то как я могу решить проблему.Может ли следующий Singleton быть небезопасным в многопоточной среде?

Я думаю, что в том числе весь блок get() уменьшит эффективность, потому что будет так много переменных конфигурации, которые необходимо читать тысячи раз в секунду из разных частей программы с помощью этого метода get().

public class ConfsDBLoader { 

    private static ConfsDBLoader INSTANCE = null; 
    private static final Object lock = new Object(); 

    private ConfsDBLoader() { //Codes loading the db objects 
    } 

    public static ConfsDBLoader get(){ 
     if(INSTANCE != null){ 
      return INSTANCE; 
     } else { 
      synchronized(lock){ 
       if(INSTANCE == null){ 
        INSTANCE = new ConfsDBLoader(); 
       } 
       return INSTANCE; 
      } 
     } 
    } 

} 

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

+1

Я предполагаю, что вы знаете, есть более простые варианты, которые были вокруг около десяти лет. Можете ли вы сообщить нам, что вы считали и почему они не подходят? –

+1

Вы используете очень старый и очень известный анти-шаблон. Это не потокобезопасно. Второй вызывающий абонент может найти ненулевую INSTANCE, в то время как первый вызывающий абонент все еще инициализирует ее. – gnasher729

+0

Вы имеете в виду, что я должен вложить два синхронизированных? Но это не эффективно! – Johnny

ответ

2

Нет. Синхронизация недостаточно, чтобы убедиться, что вы видите правильное значение на INSTANCE. Вы можете увидеть непустой, но поврежденный экземпляр, если ваш ConfsDBLoader, потому что он может быть неправильно сконструирован к тому моменту, когда другой поток вызывает getInstance().

У вас есть 3 варианта:

  • нетерпеливого Initialize и сделать окончательный
  • Синхронизировать весь метод
  • Сделать INSTANCE volatile
+0

Я отклоняю первые два, но будет ли он работать только с волатильным ключевым словом ?! Вот в чем я сомневаюсь. И будет ли это достаточно эффективным? – Johnny

+0

@Johnny Определите, что вы подразумеваете под «достаточно эффективным»? –

+0

@Johnny синхронизация всего метода имеет некоторые накладные расходы, но как часто вы будете называть метод get? В какой-то момент вы будете кэшировать локальный экземпляр в своем классе, верно? Если бы мне пришлось выбирать между ними, и загрузка объекта с нетерпением не была проблемой, я бы просто выбрал вариант 1. – coffeeaddict

Смежные вопросы