Введение
В программировании идиомом инициализации по требованию держателя (дизайн-паттерна) является ленивый загруженный синглтон. Во всех версиях Java, идиома позволяет безопасную, высококонкурентную ленивую инициализацию статических полей с хорошей производительностью. public class Что-то { private Что-то {} private статический класс LazyHolder { static final Что-то INSTANCE = new Что-то ; } public static Что-то getInstance { return LazyHolder. ИНСТАНЦИЯ; } } Реализация идиома зависит от фазы инициализации выполнения в виртуальной машине Java (JVM), как указано в спецификации языка Java (JLS). Когда класс Something загружается JVM, класс проходит инициализацию. Поскольку у класса нет никаких статических переменных для инициализации, инициализация завершается тривиально. Статика определения класса LazyHolder в нем не инициализируется, пока JVM не определит, что LazyHolder должен быть выполнен. Статический класс LazyHolder выполняется только тогда, когда статический метод getInstance вызван на классе Something, и в первый раз, когда это произойдет, JVM загрузит и инициализирует класс LazyHolder. Инициализация класса LazyHolder приводит к инициализации статической переменной INSTANCE путем выполнения (частного) конструктора для внешнего класса Something. Поскольку фаза инициализации класса гарантирована JLS последовательностью, то есть неконкурентностью, никакой дальнейшей синхронизации не требуется в статическом методе getInstance во время загрузки и инициализации. И поскольку фаза инициализации записывает статическую переменную INSTANCE в последовательной операции, все последующие одновременные вызовы getInstance возвращают ту же самую правильно инициализированную INSTANCE без каких-либо дополнительных накладных затрат на синхронизацию.
private Something {}
private static class LazyHolder {
static final Something INSTANCE = new Something ;
}
public static Something getInstance {
return LazyHolder. INSTANCE;
}
}
The implementation of the idiom relies on the initialization phase of execution within the Java Virtual Machine (JVM) as specified by the Java Language Specification (JLS). When the class Something is loaded by the JVM, the class goes through initialization. Since the class does not have any static variables to initialize, the initialization completes trivially. The static class definition LazyHolder within it is not initialized until the JVM determines that LazyHolder must be executed. The static class LazyHolder is only executed when the static method getInstance is invoked on the class Something, and the first time this happens the JVM will load and initialize the LazyHolder class. The initialization of the LazyHolder class results in static variable INSTANCE being initialized by executing the (private) constructor for the outer class Something. Since the class initialization phase is guaranteed by the JLS to be sequential, i. e., non concurrent, no further synchronization is required in the static getInstance method during loading and initialization. And since the initialization phase writes the static variable INSTANCE in a sequential operation, all subsequent concurrent invocations of the getInstance will return the same correctly initialized INSTANCE without incurring any additional synchronization overhead.
Кавеат
Хотя реализация является эффективным кэшем "одиночного" стержня без накладных затрат на синхронизацию и лучшего исполнения, чем бесконтактная синхронизация, идиом может использоваться только тогда, когда конструкция Something гарантирована не провалится. В большинстве реализаций JVM, если конструкция Something не удается, последующие попытки инициализировать его из того же загрузчика классов приведут к сбою NoClassDefFoundError.