создание экземпляров Java - PullRequest
9 голосов
/ 16 января 2011

Я нашел три способа создания экземпляра Singleton, но у меня есть сомнения относительно того, является ли какой-либо из них лучшим из существующих. Я использую их в многопоточной среде и предпочитаю ленивую реализацию.
Образец 1:

private static final ClassName INSTANCE = new ClassName();

public static ClassName getInstance() {
    return INSTANCE;
}

Образец 2:

private static class SingletonHolder { 
    public static final ClassName INSTANCE = new ClassName();
}

public static ClassName getInstance() {
    return SingletonHolder.INSTANCE;
}

Образец 3:

private static ClassName INSTANCE;

public static synchronized ClassName getInstance()
{
    if (INSTANCE == null)
        INSTANCE = new ClassName();

    return INSTANCE;
}

В проекте, которым я пользуюсь, везде используется Sample 2, но мне больше нравится Sample 3. Существует также версия Enum, но я просто не понимаю.

Вопрос здесь - в каких случаях я не должен / не должен использовать какие-либо из этих вариантов? Хотя я не ищу длинных объяснений (есть много других тем по этому поводу, но все они в конечном итоге превращаются в спор о ИМО), я бы хотел, чтобы это было понятно несколькими словами.

Ответы [ 4 ]

20 голосов
/ 16 января 2011

Самый безопасный и простой способ реализовать синглтон в Java - это использовать перечисления (как вы упомянули):

public enum ClassName {
    INSTANCE;

    // fields, setters and getters
}

Семантика перечисления гарантирует, что будет только один INSTANCE

Если вы не используете подход enum, вы должны позаботиться о многих аспектах, таких как условия гонки и рефлексия.Я ломал синглтоны некоторых фреймворков и злоупотреблял ими, потому что они не были написаны должным образом.Перечисление гарантирует, что никто не сломает его.

4 голосов
/ 16 января 2011

Образец 1 не использует отложенную инициализацию.

Образцы 2 и 3 ленивы. В примере 2 используется идиома владельца инициализации (IODH) , у которой нет накладных расходов на синхронизацию . Поэтому он быстрее, чем образец 3.

В Effective Java (пункт 3) Джошуа Блох рекомендует, чтобы одноэлементный тип перечисления был наилучшим способом реализации синглтона .

Однако, если вы не уверены в типе enum, придерживайтесь IODH.

2 голосов
/ 16 января 2011

Прежде всего, убедитесь, что вам нужен синглтон, и что вы хотите предоставить ему доступ на глобальном уровне.Я обнаружил, что во многих случаях клиентам синглтона не нужно знать, что это синглтон.Скорее, им просто нужно получить услугу, когда они будут созданы.

Таким образом, независимо от того, как вы получаете синглтон (если вообще), рассмотрите возможность изменения способа, которым ваши классы получают доступ к этому объекту.Хотя это означает изменение конструкторов и изменение «изменений дистрибутива», я обнаружил, что структуры внедрения зависимостей снижают стоимость.Структура DI также может позаботиться об экземпляре синглтона (например, это делает Guice).

Помимо этого.Вариант 3 - это типичная и наиболее распространенная (и многопоточная) версия, с которой я знаком.Вариант 1 в основном для не ленивой инициализации (не всегда приемлемо).Я никогда не видел 2 использованных.

1 голос
/ 16 января 2011

Образец 1: используйте, если вам не нужен ленивый синглтон.
Пример 2: Никогда не используйте - это сбивает с толку слишком много классов. И внутренний класс, содержащий только одну переменную, кажется немного ненужным. Образец 3: Это ленивый синглтон. Используйте его, если вам это нужно.

...