Изучив предложенные в статьях «Правильный Singleton в Java» и «Реализация Singleton в JAVA» варианты решений и «пораскинув мозгами», я предположил, что смогу представить еще два похожих друг на друга варианта создания Singleton'а, практически лишенных многих недостатков тех решений, которые были изложены ранее в упомянутых статьях. Но хочу начать с постановки задач, решение которых определит, добились ли мы желаемого результата.
Требования:
1. Потокобезопасность
2. Сериализуемость изменений ссылки на объект-Singleton
3. Управляемость создания объекта в блоке try-catch
4. Создание объекта-Singleton вне конструктора
5. Несериализуемое получение ссылки на объект-Singleton, обеспечивающее лучшую производительность.
6. «Ленивая» инициализация объекта-Singleton
Вариант 1
В предложенном варианте, вызов синхронизируемого метода для создания ссылки на объект происходит из так называемого статического инициализатора объекта, который, по сути, выполняется на том же уровне, что и инициализация переменных-членов объекта, выполняется до вызова конструктора и должен быть сериализуем «by design». Но так как моя надежда на самосериализуемость блока-инициализатора не велика, я снабдил статическую ссылку на объект-Singleton модификатором volatile, обеспечивающим непротиворечивость значений статической переменной в разных потоках, а статический метод создания объекта-Singleton снабдил модификатором synchronized, гарантирующим одновременное выполнение данного метода только в одном потоке.
Второй вариант похож на первый тем, что использует тот же принцип инициализации — из блока-инициализатора, но отличен отсутствием модификатора volatile у статической ссылки на объект-Singleton в угоду производительности, а синхронизация создания объекта основывается на блокировке объекта-члена класса с ранее выполненной инициализацией. При этом использована идея, предложенная в комментариях к статье «Правильный Singleton в Java».
Вариант 2
Требования:
1. Потокобезопасность
2. Сериализуемость изменений ссылки на объект-Singleton
3. Управляемость создания объекта в блоке try-catch
4. Создание объекта-Singleton вне конструктора
5. Несериализуемое получение ссылки на объект-Singleton, обеспечивающее лучшую производительность.
6. «Ленивая» инициализация объекта-Singleton
Вариант 1
public class Singleton {
private static volatile Singleton instance;
static {
System.out.print("Singleton class Initializator\r\n");
try {
InitSingleton();
} catch (Exception e) {
System.out.print("Exception occurred\r\n");
}
}
private static synchronized void InitSingleton() {
if (instance == null) instance = new Singleton();
}
public Singleton() {
System.out.print("Singleton has been initialized\r\n");
}
public static Singleton getInstance() {
return instance;
}
}
В предложенном варианте, вызов синхронизируемого метода для создания ссылки на объект происходит из так называемого статического инициализатора объекта, который, по сути, выполняется на том же уровне, что и инициализация переменных-членов объекта, выполняется до вызова конструктора и должен быть сериализуем «by design». Но так как моя надежда на самосериализуемость блока-инициализатора не велика, я снабдил статическую ссылку на объект-Singleton модификатором volatile, обеспечивающим непротиворечивость значений статической переменной в разных потоках, а статический метод создания объекта-Singleton снабдил модификатором synchronized, гарантирующим одновременное выполнение данного метода только в одном потоке.
Второй вариант похож на первый тем, что использует тот же принцип инициализации — из блока-инициализатора, но отличен отсутствием модификатора volatile у статической ссылки на объект-Singleton в угоду производительности, а синхронизация создания объекта основывается на блокировке объекта-члена класса с ранее выполненной инициализацией. При этом использована идея, предложенная в комментариях к статье «Правильный Singleton в Java».
Вариант 2
public class Singleton {
private static Singleton instance;
private static final Object lock = new Object();
private static boolean isInitialized = false;
static {
System.out.print("Singleton class Initializator\r\n");
try {
synchronized (lock) {
if (!isInitialized)
if (instance == null) {
instance = new Singleton();
isInitialized = true;
}
}
} catch (Exception e) {
System.out.print("Exception occurred\r\n");
}
}
public Singleton() {
System.out.print("Singleton has been initialized\r\n");
}
public static Singleton getInstance() {
return instance;
}
}