предисловие
Только лысина может стать сильнее
Оглядываясь назад на фронт:
Я изначально планировал обновить его не так скоро, но я некоторое время чистил книги Spring. Глядя на Spring, мы часто видим слова «singleton» и «factory».
Итак, давайте сначала поговорим о шаблонах проектирования singleton и factory.Эти два шаблона также очень распространены.Я вижу эти два шаблона во многих писаниях~
В этой статье в основном объясняетсяодноэлементный шаблон проектированияЕсли есть не то место, я надеюсь включить больше, я не стесняюсь исправить в комментарии!
Обзор одноэлементного шаблона
Определение одноэлементного шаблона простое:Экземпляр может быть создан в классе, так что назовите его синглтоном!
Итак, когда мы используем шаблон singleton? ?
- Затем мы думаем, что, поскольку в классе может быть создан только один экземпляр, можно сказать, что это связано сСостояние класса не зависит от объекта.
- Создание объектов и управление ими часто требует больших ресурсов., нам просто нужно создать объект, чтобы использовать его!
Учащиеся, изучавшие Java Web, могут знать:
- Сервлеты являются синглтонами
- Struts2 поддерживает несколько экземпляров
- SpringMVC является одноэлементным
Итак, поскольку несколько экземпляров часто создают объекты и нуждаются в управлении объектами, зачем Struts2 нужно несколько экземпляров? ?
- главным образом из-зауровень дизайнаПроблема со Struts2 заключается в следующем.Основываясь на классе перехвата Filter, движок ognl вводит переменные.所以它要设计成多例的~
Можно сделать это с одним объектом, не создавая несколько объектов! Это может уменьшить наши накладные расходы на пространство и память~
Возможно, некоторые люди еще раз подумают: мы используем静态类.doSomething()
и вызов метода с использованием одноэлементного объектаэффект такой жеда.
- Да, эффект тот же. использовать
静态类.doSomething()
воплощает в себеоснованный на объекте, а использование одноэлементного шаблона проектирования отражаетобъектно-ориентированный.
2. Напишите код для одноэлементного шаблона
Написание кода для одноэлементного паттерна на самом деле очень простое, оно разбито на три шага:
- Сделать конструктор закрытым
- Внутренний создать экземпляр класса
- Предоставляет способ получить уникальный экземпляр
2.1 Голодный китайский стиль
В соответствии с вышеуказанными шагами мы можемЛегко создавайте одноэлементные объекты.
public class Java3y {
// 1.将构造函数私有化,不可以通过new的方式来创建对象
private Java3y(){}
// 2.在类的内部创建自行实例
private static final Java3y java3y = new Java3y();
// 3.提供获取唯一实例的方法
public static Java3y getJava3y() {
return java3y;
}
}
Мы называем этот код: "голодный китаец":
- Объект создается, как только он появляется,Если экземпляр никогда не используется от начала до конца, это приведет к потере памяти..
2.2 Простой ленивый стиль
Поскольку объект создается сразу после его произнесения, это приведет к трате памяти, если он не используется:
- Итак, мы проектируемСоздать объекты при необходимости!
public class Java3y {
// 1.将构造函数私有化,不可以通过new的方式来创建对象
private Java3y(){}
// 2.1先不创建对象,等用到的时候再创建
private static Java3y java3y = null;
// 2.1调用到这个方法了,证明是要被用到的了
public static Java3y getJava3y() {
// 3. 如果这个对象引用为null,我们就创建并返回出去
if (java3y == null) {
java3y = new Java3y();
}
return java3y;
}
}
Приведенная выше строка кода работает? ? Он работает в однопоточной среде,Не работает в многопоточной среде!
- Если вы не знаете, почему это не работает в многопоточной среде, вы можете обратиться к моему предыдущему сообщению в блоге:Базовые знания многопоточности! После прочтения изучение многопоточности может сделать больше с меньшими затратами
Это легко решить, мыПросто заблокируйте егов настоящее время:
2.3 Ленивый стиль механизма двойного обнаружения (DCL)
Вышеупомянутый метод прямой блокировки метода недостаточно хорош, потому что вметод со встроенным замкомВ многопоточной среде производительность будет ниже, поэтому мы можемУменьшить диапазон замков.
public class Java3y {
private Java3y() {
}
private static Java3y java3y = null;
public static Java3y getJava3y() {
if (java3y == null) {
// 将锁的范围缩小,提高性能
synchronized (Java3y.class) {
java3y = new Java3y();
}
}
return java3y;
}
}
Приведенный выше код работает? ?нет, потому что хотя блокировка и добавлена, все равно естьможно создать два объектаот:
- Поток A и поток B вызываются одновременно
getJava3y()
метод, они одновременно судятjava==null
, все результаты нулевые, поэтому введите блок кода if - В этот момент поток A получает управление процессором --> входит в блок кода синхронизации --> создает объект --> возвращает объект
- После завершения потока A поток B в это время получает контроль над ЦП. То же самое --> введите блок кода синхронизации --> создайте объект --> верните объект
- Очевидный: классы Java3yвозвращено более одного экземпляра! Таким образом, приведенный выше код не будет работать!
Некоторые одноклассники могут подумать, что я хвастаюсь, но этого недостаточно, чтобы запереть? Давайте проверим это:
public class TestDemo {
public static void main(String[] args) {
// 线程A
new Thread(() -> {
// 创建单例对象
Java3y java3y = Java3y.getJava3y();
System.out.println(java3y);
}).start();
// 线程B
new Thread(() -> {
// 创建单例对象
Java3y java3y = Java3y.getJava3y();
System.out.println(java3y);
}).start();
// 线程C
new Thread(() -> {
// 创建单例对象
Java3y java3y = Java3y.getJava3y();
System.out.println(java3y);
}).start();
}
}
Как вы можете видеть, напечатанный объектне одиниз!
Великие программисты думают еще раз: при вводе блока синхронизированного кодаЗатем определите, существует ли объект или нет.!
- Итак, со следующим кодом
public class Java3y {
private Java3y() {
}
private static Java3y java3y = null;
public static Java3y getJava3y() {
if (java3y == null) {
// 将锁的范围缩小,提高性能
synchronized (Java3y.class) {
// 再判断一次是否为null
if (java3y == null) {
java3y = new Java3y();
}
}
}
return java3y;
}
}
На самом деле не стабильно!Здесь будут проблемы с изменением порядка:
Первоначально я хотел проверить влияние проблемы с переупорядочением, но я не проверял его ~~~ Я надеюсь, что есть соответствующий тестовый код, который подскажет мне, как его измерить....
Это также очень просто решить, просто добавьте ключевое слово volatile,Volatile имеет барьер памяти!
Специальные справочные материалы:
- Ууху. Call.com/question/35…---- Блокировки с двойной проверкой терпят неудачу, потому что инициализация объекта не является атомарной?
- если eve.com/double check…--- Примечание о «Недействительности блокировки с двойной проверкой»
- № OSCHINA.net/U/866190/ Первоначально…---- правильное использование двойных проверенных замков (DCL)
Итак, полный код DCL выглядит так:
public class Java3y {
private Java3y() {
}
private static volatile Java3y java3y = null;
public static Java3y getJava3y() {
if (java3y == null) {
// 将锁的范围缩小,提高性能
synchronized (Java3y.class) {
// 再判断一次是否为null
if (java3y == null) {
java3y = new Java3y();
}
}
}
return java3y;
}
}
Снова:
2.4 Ленивый стиль статического внутреннего класса
также можно использоватьУмный способ статических внутренних классовЧтобы реализовать синглтон-шаблон! Его принцип это:
- когда любой потокпервый звонок
getInstance()
Когда SingletonHolder загружен и инициализирован, статический инициализатор выполнит инициализацию Singleton. (Инициализируется при вызове! ) - Гарантии безопасности потоков, предоставляемые Java при инициализации статических данных. (поэтому нет необходимости в какой-либо синхронизации)
public class Java3y {
private Java3y() {
}
// 使用内部类的方式来实现懒加载
private static class LazyHolder {
// 创建单例对象
private static final Java3y INSTANCE = new Java3y();
}
// 获取对象
public static final Java3y getInstance() {
return LazyHolder.INSTANCE;
}
}
статический внутренний класс таким образомнастоятельно рекомендуетсяиз! Многие люди, которые не сталкивались с паттерном singleton, не знают, что существует такой метод записи, который очень оптимизирован и эффективен!
Использованная литература:
- Ууху. Call.com/question/35…---- Как шаблон java singleton передает внутренний статический класс?
2.5 Реализация перечисления
Использовать перечисление очень просто:
public enum Java3y3y {
JAVA_3_Y_3_Y,
}
Какая от этого польза? ? Реализован способ перечисления:
- Просто, просто напишите
- предотвратить множественное создание экземпляров, даже перед лицом сложных атак сериализации или отражения (безопасно)!
Этот тоже рекомендуется!
3. Резюме
В общем, есть 5 способов написать шаблон singleton:
- голодный китаец
- Простой ленивый (метод блокировки)
- Двойное обнаружение и блокировка DCL (расширенный ленивый стиль)
- Статический внутренний класс реализует ленивый стиль (наиболее рекомендуемый способ написания)
- Метод перечисления (самый безопасный и лаконичный способ написания)
Я думаю, что это будет написано завтразаводской узорДа, пожалуйста, ждите этого~~~
Использованная литература:
- Дзен шаблонов проектирования
- woo woo woo.cn blog on.com/ противный цвет ах 125/ ах…---Зачем использовать шаблон singleton?
- zhuanlan.zhihu.com/p/32310340--- Рождество, давайте поговорим о шаблоне singleton
- zhuanlan.zhihu.com/p/34406410--- Подробный режим одного примера
- Woohoo.now A magic.net/library is/VE…--- Несколько моментов, на которые следует обратить внимание при использовании шаблона singleton
- zhuanlan.zhihu.com/p/23713957--- Шаблоны проектирования Java (1) — шаблон Singleton
Если в статье есть какие-либо ошибки, пожалуйста, поправьте меня, и мы сможем общаться друг с другом. Учащиеся, привыкшие читать технические статьи в WeChat и желающие получить больше ресурсов по Java, могутОбратите внимание на публичный аккаунт WeChat: Java3y.
Оглавление Навигация по статьям: