Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Есть ли проблемы в многопоточной среде с шаблоном Singleton?

Автор вопроса: Sharad AhireОтветов: 7

Я реализовал класс Singleton, как показано ниже:

public class Singleton {

    private static  Singleton instance = null;


    private Singleton() {
    }

private synchronized static void createInstance() {
    instance = new Singletone();
}


    public static Singleton getInstance() {
        if(instance == null){
            createInstance();
        }
        return instance;
    }

}

Но я хочу знать, является ли это правильной реализацией синглтона. Есть ли проблемы в многопоточной среде.

  • Опечатка: это Singleton, а не Singletone. И да, это не потокобезопасный синглтон. zengr 30.11.2011
  • возможный дубликат безопасного потока java singleton zengr 30.11.2011
  • Возможный дубликат: stackoverflow .com/questions/70689/ Alex K 30.11.2011

javamultithreadingdesign-patternssingleton

Ответы

Ответ 1 · рейтинг 7 · AlexR

Ваша реализация почти правильная. Проблема в том, что он не является потокобезопасным. 2 отдельных потока могут войти в getInstance() одновременно, проверьте, что экземпляр имеет значение null, а затем создайте 2 экземпляра вашего класса. Вот исправление:

public static synchronized Singletone getInstance() {
    if(instance == null){
        createInstance();
    }
    return instance;
}

Обратите внимание на слово synchronized.

Ответ 2 · рейтинг 7 · zengr

public enum Singleton {
    INSTANCE;
    private int val;

    public int getVal() {
        return val;
    }
}

Использование:

Singleton.INSTANCE.getVal();

Это идеальный синглтон для версий Java > 5.0, где у вас есть поддержка enum.

Также упоминается в "Эффективной Java" Джошуа Блоха. Сообщение в блоге об этом здесь: Enum Singleton

Обновление:
Кроме того, используйте синглтоны только тогда, когда вы на 100 % уверены, что они вам нужны! Это убивает тестируемость кода! Но вы не можете избежать его в некоторых местах, скажем, на Фабрике.
Но, пожалуйста, не злоупотребляйте им, используйте его там, где он вам действительно нужен. Поймите его использование.

Ответ 3 · рейтинг 2 · Jakub Korab

Лучший механизм, с которым я столкнулся, кроме перечисления выше, называется статической инициализацией. При этом вы полагаетесь на гарантии модели памяти Java, поэтому она всегда работает. Вот фрагмент из ответа на другой вопрос, который демонстрирует это:

class Singleton {
   static class SingletonHolder {
      static final Singleton INSTANCE = new Singleton();
   }
   public static Singleton instance() {
      return SingletonHolder.INSTANCE;
   }
}

Объект класса SingletonHolder с экземпляром Singleton будет создан при первом вызове SingletonHolder.INSTANCE.

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

Ответ 4 · Steve Rukuts

Это правильная реализация одноэлементного шаблона, хотя на самом деле вам не нужен метод createInstance; вы можете просто встроить это в getInstance. Кроме того, оно пишется "Singleton", без буквы "e" в конце.

Гипотетически вы можете создать проблему в многопоточной среде. Если два указателя фрейма входят в getInstance одновременно, тот, который вошел первым, может получить экземпляр Singleton, а второй - другой экземпляр.

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

Ответ 5 · bsrykt

Для реализации ленивой инициализации, как в вашем случае, метод getInstance() должен быть синхронизирован для обеспечения безопасности потоков.

public static synchronized Singleton getInstance()

Или вы можете просто инициализировать его во время загрузки класса, что уже является потокобезопасным.

private static  Singleton instance = new MySingleton();

Ответ 6 · Buhake Sindi

Синглтон не является потокобезопасным. Именно по этой причине была введена блокировка с двойной проверкой.

Начиная с Java SE 5 и выше, вы можете volatile свой статический экземпляр. Виртуальная машина Java будет знать, как правильно обрабатывать Singleton при выполнении нескольких потоков.

Подробнее об блокировке с двойной проверкой.

Ответ 7 · рейтинг -1 · vertti

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

См. http://java.sun.com/developer/technicalArticles/Programming/singletons/ для краткого изложения этих проблем.

О, и это синглтон, а не синглтон. :)

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы