Одноэлементный режим — самый простой и наиболее часто используемый среди 23 режимов GOF, а также именно его больше всего любят тестировать интервьюеры. Поскольку одноэлементный шаблон достаточно прост, написание кода одноэлементного шаблона может быть выполнено за несколько минут, поэтому интервьюер обычно выбирает одноэлементный шаблон в качестве вопроса в шаблоне проектирования. Давайте разделим singleton-режим на несколько пунктов, и поговорим о том, где интервьюер может вас протестировать?
Смысл одноэлементного паттерна
Обычно интервьюер спросит вас очень вообще, что такое рисунок Singleton? Какой болевой момент является синглтон-шаблон, используемый для решения? Что бы мы сделали без рисунка Singleton? У Singleton Pattern есть какие-то недостатки?
Одноэлементный шаблон является одним из самых простых шаблонов проектирования и относится к шаблону создания, который обеспечивает способ создания объектов, гарантируя, что будет создан только один объект. Основная цель этого шаблона проектирования заключается в том, что во всей системе может появиться только один экземпляр класса, то есть класс имеет только один объект. Проблема, решаемая одноэлементным режимом, заключается в экономии ресурсов и времени в двух аспектах:
1. Из-за часто используемых объектов время, затрачиваемое на создание объектов, можно не учитывать, что важно для этих тяжеловесных объектов.
2. Поскольку нет необходимости часто создавать объекты, наша нагрузка на GC также снижается, и в GC будет STW (остановить мир), что также экономит время GC с этой точки зрения. Недостатки одноэлементного шаблона: проектирование и разработка простого одноэлементного шаблона относительно просты, но сложный одноэлементный шаблон должен учитывать проблемы параллелизма, такие как безопасность потоков, что вносит некоторую сложность.
Расширения: какие расширения можно сделать из вашего ответа? Мы говорили о GC, и возможно, что вас будут спрашивать о GC, STW и других знаниях в это время. Говоря о недостатках, я говорил о сложном паттерне singleton, В это время вас могут попросить разработать отличный одноэлементный шаблон. Как бы вы его разработали и реализовали?
дизайн одноэлементного шаблона
Обычно интервьюер спрашивает вас, как спроектировать шаблон singleton и на какие аспекты нужно обратить внимание? В общем, каковы методы реализации одноэлементного паттерна?
При разработке одноэлементного шаблона необходимо учитывать несколько факторов:
- безопасность резьбы - ленивая загрузка -Безопасность кода: например, предотвращение атак сериализации, предотвращение атак отражения (предотвращение вызовов закрытых методов отражением) - Коэффициент производительности
Вообще говоря, когда мы идем в Baidu для поиска в Интернете, существует около 7 или 8 видов реализации, Ниже приведены ключевые моменты, которые нужно знать. Голодный, ленивый (потокобезопасный, поточно-небезопасный), дважды проверенный (DCL) (акцент), внутренние классы и перечисления (акцент), Сравните реализации ниже:
|
потокобезопасность |
хороший параллелизм |
Может быть ленивой загрузки |
Безопасность сериализации/десериализации |
Сопротивление атакам отражения |
|
---|---|---|---|---|---|---|
голодный китаец |
Y |
Y |
|
|
|
|
ленивый |
не заблокирован |
|
Y |
Y |
|
|
заблокирован |
Y |
|
Y |
|
|
|
DCL |
Y |
Y |
Y |
|
|
|
статический внутренний класс |
Y |
Y |
Y |
|
|
|
перечислить |
Y |
Y |
|
Y |
Y |
Расширение: О реализации каждого режима мы говорили выше.В настоящее время весьма вероятно, что вас попросят написать код каждого режима. Конечно, вас также могут спросить о безопасности потоков, безопасности кода и других знаниях.
режим голодного человека
Код для режима голодного человека выглядит следующим образом:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
Код голодного китайского режима относительно прост.Объект определяется как частный статический в классе.Через getInstance() механизм classLoader Java гарантирует, что объект-одиночка уникален. расширение:
Можно спросить, когда instance инициализируется?
Класс Singleton будет инициализирован при его загрузке.Хотя спецификация виртуальной машины Java не имеет обязательного ограничения на то, когда начинать процесс загрузки класса, для инициализации класса спецификация виртуальной машины строго оговаривает наличие только четырех ситуации, которые должны быть исправлены немедленно. Класс инициализируется. При встрече с четырьмя инструкциями байт-кода new, getStatic, putStatic или invokeStatic, если класс не был инициализирован, его инициализация должна быть запущена в первую очередь. Наиболее распространенные сценарии Java-кода для создания этих 4 инструкций: 1) использовать ключевое слово new для создания экземпляра объекта 2) читать статическое поле класса (за исключением статических полей, которые окончательно изменены и помещают результат в константу пул во время компиляции)) 3) Установить статическое поле класса (за исключением статических полей, которые окончательно изменены, и результат был помещен в постоянный пул во время компиляции) 4) Вызвать статический метод класса
жизненный цикл класса
Жизненный цикл класса обычно проходит пять этапов: загрузка, подключение, инициализация, использование и выгрузка.
механизм загрузки классов
Здесь мы можем поговорить о родительской модели делегирования classloader.
Двойная проверка DCL
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
Синхронизированный блок может гарантировать, что будет создан только один объект. Но, добавив слой суждения за пределами синхронизированного, вы больше не сможете войти в синхронизированный блок после создания объекта. Это решение не только уменьшает детализацию блокировок, но также обеспечивает безопасность потоков и значительно повышает производительность.
В то же время следует отметить, что здесь необходимо сказать о volatile, это очень критично, Volatile обычно используется для многопоточной видимости, но здесь он используется для предотвращения переупорядочения инструкций.
расширение:
Зачем вам летучий? Какая польза от volatile?
- Прежде всего, чтобы ответить на видимость, это не вызывает сомнений, а затем может протестировать модель памяти Java.
- Предотвратить переупорядочивание инструкций: предотвращение переупорядочивания инструкций во время создания New Singleton, чтобы другие потоки не получали неинициализированные объекты. Предложение instance = new Singleton() не является атомарной операцией.На самом деле в JVM это предложение, вероятно, делает следующие три вещи. 1. Выделить память для экземпляра 2. Вызвать конструктор Singleton для инициализации переменных-членов 3. Указать объект экземпляра на выделенное пространство памяти (после этого шага экземпляр будет ненулевым) Но есть оптимизации для переупорядочивания инструкций в JVM-компиляторе JVM. То есть порядок второго и третьего шагов выше не гарантируется, и окончательный порядок выполнения может быть 1-2-3 или 1-3-2. Если это последнее, он будет вытеснен потоком 2 до того, как будет выполнен 3, а 2 не будет выполнен.В это время экземпляр уже не равен нулю (но не инициализирован), поэтому поток 2 будет напрямую возвращать экземпляр, использовать его, и сообщить об ошибке.
- Кстати, можно также сказать, что принцип volatile использует барьеры памяти.
Разговор о разнице между синхронизированным и изменчивым
Тут можно исходить из того, что synchronized может гарантировать атомарность, volatile гарантировать не может, и что synchronized — это тяжеловесная блокировка, или вообще разница между ним и Lock и так далее.
Как обычно достигается безопасность потоков?
- Взаимоисключающая синхронизация. Например, блокировка, синхронизация
- Неблокирующая синхронизация. Такие как каз.
- не синхронизировано. Например, threadLocal, локальные переменные.
перечисляемый класс
public enum Singleton{
INSTANCE;
}
Создание экземпляра перечисления по умолчанию является потокобезопасным, поэтому не нужно беспокоиться о потокобезопасности. Это также рекомендуемый шаблон в Effective Java. Наконец, с помощью класса перечисления он может автоматически избежать атак сериализации/десериализации, а также атак отражения (классы перечисления не могут быть сгенерированы отражением).
Суммировать
Хотя шаблон singleton выглядит простым, он имеет много базовых знаний в Java, таких как статический модификатор, синхронизированный модификатор, модификатор volatile, перечисление и т. д. Каждая точка знаний здесь может стать тестовой площадкой для интервьюера, а отдельный кейс — это только введение, в конце концов, это зависит от того, насколько вы освоили. Зависит от вашей широты и глубины.
Наконец, эта статья была включена в JGrowing, всеобъемлющий и отличный маршрут изучения Java, совместно созданный сообществом.Если вы хотите участвовать в обслуживании проектов с открытым исходным кодом, вы можете создать его вместе.Адрес github:GitHub.com/Java растет…Пожалуйста, дайте мне маленькую звезду.
Если вы считаете, что эта статья полезна для вас, или вы хотите получить статьи из последующих глав заранее, или если у вас есть какие-либо вопросы и вы хотите предоставить бесплатный VIP-сервис 1 на 1, вы можете подписаться на мой официальный аккаунт.Ваше внимание и пересылка являются для меня самой большой поддержкой. O(∩_∩)O: