Ваша реализация почти правильная. Проблема в том, что он не является потокобезопасным. 2 отдельных потока могут войти в getInstance() одновременно, проверьте, что экземпляр имеет значение null, а затем создайте 2 экземпляра вашего класса. Вот исправление:
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();
Начиная с Java SE 5 и выше, вы можете volatile свой статический экземпляр. Виртуальная машина Java будет знать, как правильно обрабатывать Singleton при выполнении нескольких потоков.
Ваша реализация кажется просто отличной. Многопоточность в одной JVM не является проблемой для такого рода одноэлементных проблем, но вызовет проблемы в кластере (две или более JVM).