Реализовать паттерн Singleton

11. Реализовать паттерн Singleton

Условие задачи:
Необходимо реализовать паттерн Singleton.

Класс должен:

  • иметь только один экземпляр в рамках ClassLoader;

  • запрещать создание объекта через new извне класса;

  • предоставлять глобальную точку доступа к экземпляру;

  • быть потокобезопасным;

  • создавать экземпляр лениво — только при первом обращении.


Спойлеры к решению

Подсказки
💡 Конструктор должен быть private.
💡 Для ленивой и потокобезопасной инициализации можно использовать Initialization-on-demand holder idiom.
💡 Вложенный статический класс загружается только при первом обращении к нему.
💡 Инициализация статических полей класса в Java выполняется потокобезопасно.

Решение
public final class Singleton {

    private Singleton() {
    }

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

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

Пример использования:

Singleton first = Singleton.getInstance();
Singleton second = Singleton.getInstance();

System.out.println(first == second); // true

Приватный конструктор:

private Singleton() {
}

не позволяет создать экземпляр обычным способом:

new Singleton();

Метод:

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

обращается к вложенному классу SingletonHolder.

Именно при первом обращении к нему создаётся экземпляр:

private static final Singleton INSTANCE = new Singleton();

Инициализация класса в JVM выполняется потокобезопасно, поэтому дополнительный synchronized здесь не требуется.

Свойства такого решения:

  • ленивая инициализация;

  • потокобезопасность;

  • отсутствие синхронизации при каждом вызове getInstance();

  • простая реализация.

Класс дополнительно объявлен final, чтобы его нельзя было расширить наследованием.

Альтернативный вариант Singleton в Java — enum:

public enum Singleton {
    INSTANCE
}

Он особенно удобен, если не требуется именно реализация через обычный класс.