В программной инженерии идиома инициализации по запросу владельца (шаблон проектирования ) - это отложенная загрузка синглтон. Во всех версиях Java эта идиома обеспечивает безопасную одновременную отложенную инициализацию статических полей с хорошей производительностью.
public class Something {private Something () {} частный статический класс LazyHolder {static final Something INSTANCE = new Something () ; } public static Something getInstance () {return LazyHolder.INSTANCE; }}
Реализация идиомы основана на фазе инициализации выполнения в виртуальной машине Java (JVM), как указано в спецификации языка Java (JLS). Когда класс Something
загружается JVM, класс проходит инициализацию. Поскольку в классе нет статических переменных для инициализации, инициализация завершается тривиально. Определение статического класса LazyHolder
внутри него не инициализируется, пока JVM не определит, что LazyHolder
должен быть выполнен. Статический класс LazyHolder
выполняется только тогда, когда статический метод getInstance
вызывается в классе Something
, и в первый раз, когда это происходит, JVM загружает и инициализирует LazyHolder
класс. Инициализация класса LazyHolder
приводит к инициализации статической переменной INSTANCE
путем выполнения (частного) конструктора для внешнего класса Something
. Поскольку JLS гарантирует, что фаза инициализации класса будет последовательной, то есть не параллельной, в статическом методе getInstance
во время загрузки и инициализации не требуется дальнейшей синхронизации. А поскольку на этапе инициализации статическая переменная INSTANCE
записывается в последовательной операции, все последующие параллельные вызовы getInstance
будут возвращать тот же правильно инициализированный INSTANCE
без каких-либо дополнительные накладные расходы на синхронизацию.
Хотя реализация представляет собой эффективный потокобезопасный «одноэлементный» кэш без накладные расходы на синхронизацию и более эффективную, чем неконтролируемая синхронизация, идиома может использоваться только в том случае, если конструкция Something
гарантированно не потерпит неудачу. В большинстве реализаций JVM, если построение Something
завершается неудачно, последующие попытки инициализировать его из того же загрузчика классов приведут к сбою NoClassDefFoundError
.