предисловие
Впервые я столкнулся с паттернами проектирования на прошлых зимних каникулах, тогда я изучил каждый паттерн проектирования и имел представление о паттернах проектирования на первом уровне. Я позаимствовал несколько книг по шаблонам проектирования в этом семестре и прослушал урок учителя по шаблонам проектирования, так что я лучше понимаю шаблоны проектирования. Позже я могу время от времени обновлять свое понимание шаблонов проектирования. Каждый шаблон проектирования кажется очень простым, но применить его в целостной системе очень и очень сложно. Тогда качество моей воды тоже очень и очень ограничено, а количество кода не очень велико.Я могу обобщить это, только читая книги, размышляя об опыте кодирования других людей и сочетая с проблемами, возникающими в моем собственном процессе кодирования.
Как использовать -> как его правильно использовать -> как использовать его в сочетании с другими режимами, я думаю, что это пробел, который должен преодолеть каждый разработчик.
1 Введение в шаблон Singleton
1.1 Определения
Гарантирует наличие только одного экземпляра класса и предоставляет к нему глобальную точку доступа.
1.2 Зачем использовать шаблон singleton?
В нашей системе есть некоторые объекты, которые нам нужны только по одному, например: пул потоков, кеш, диалоговое окно, реестр, объект журнала, объекты, которые действуют как драйверы устройств, такие как принтеры и видеокарты. На самом деле может быть только один экземпляр этого типа объекта.Если создается несколько экземпляров, могут возникнуть некоторые проблемы, такие как: ненормальное поведение программы, чрезмерное использование ресурсов или противоречивые результаты.
Проще говоря, использование шаблона singleton может принести следующие преимущества:
- Для часто используемых объектов время, затрачиваемое на создание объектов, можно не учитывать, что является значительным системным накладным расходом для таких тяжеловесных объектов;
- Поскольку количество новых операций уменьшается, частота использования системной памяти также будет снижена, что снизит нагрузку на сборщик мусора и сократит время паузы сборщика мусора.
1.3 Почему бы не использовать глобальные переменные, чтобы гарантировать наличие только одного экземпляра класса?
Мы знаем, что глобальные переменные делятся на статические переменные и переменные экземпляра.Статические переменные также могут гарантировать, что существует только один экземпляр класса. Пока программа загружает байт-код класса без создания каких-либо объектов экземпляра, статическим переменным будет выделено место, и статические переменные можно будет использовать.
Однако, если этот объект потребляет много ресурсов, а программа оказалась бесполезной в определенном исполнении, это приведет к пустой трате ресурсов.Используя шаблон singleton, мы можем создавать объекты, когда нам нужно их использовать, избегая, таким образом, ненужной траты ресурсов.Не только по этой причине мы должны стараться избегать использования глобальных переменных в программе, а широкое использование глобальных переменных создает трудности при отладке и обслуживании программы.
2 Реализация одноэлементного шаблона
Обычно в языке Java шаблон синглтона строится двумя способами:
- голодный человек. Относится к глобальному экземпляру синглтона, созданному во время загрузки класса.
- ленивый путь. Относится к экземпляру глобального синглтона, создаваемому при первом использовании.
Независимо от того, как они созданы, они обычно имеют следующие сходства:
- Класс синглтона должен иметь конструктор с закрытым уровнем доступа, только таким образом можно гарантировать, что экземпляр синглтона не будет создан в другом коде в системе;
- переменные-члены экземпляра и методы uniqueInstance должны быть статическими.
2.1 Голодный метод (потокобезопасность)
public class Singleton {
//在静态初始化器中创建单例实例,这段代码保证了线程安全
private static Singleton uniqueInstance = new Singleton();
//Singleton类只有一个构造方法并且是被private修饰的,所以用户无法通过new方法创建该对象实例
private Singleton(){}
public static Singleton getInstance(){
return uniqueInstance;
}
}
так называемый"Голодный путь"Другими словами, когда JVM загружает этот класс, она немедленно создает этот уникальный экземпляр singleton. Независимо от того, используете ли вы его или нет, сначала создайте его. Если он не использовался все время, он будет занимать место впустую. Типичное пространство меняет время. , каждый раз, когда вы его вызываете, нет необходимости снова судить, экономя время выполнения.
2.2 Ленивый (непоточно-ориентированные и синхронизированные поточно-ориентированные версии ключевых слов)
public class Singleton {
private static Singleton uniqueInstance;
private Singleton (){
}
//没有加入synchronized关键字的版本是线程不安全的
public static Singleton getInstance() {
//判断当前单例是否已经存在,若存在则返回,不存在则再建立单例
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
так называемый"Голодный путь"То есть экземпляр singleton создается при первом использовании, а не единственный экземпляр singleton, созданный сразу же, когда JVM загружает класс.
Но вышеприведенный метод явно небезопасен для потоков, и возникнут проблемы, если несколько потоков одновременно получат доступ к методу getInstance(). Если вы хотите обеспечить потокобезопасность, более распространенным способом является добавление ключевого слова synchronized перед методом getInstance(), как показано ниже:
public static synchronized Singleton getInstance() {
if (instance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
Мы знаем, что ключевое слово synchronized предпочитает тяжелые блокировки. Хотя ключевое слово synchronized после Java SE 1.6 в основном включает в себя: предвзятые блокировки и облегченные блокировки, введенные для снижения потребления производительности, вызванного получением и освобождением блокировок, а также различные другие оптимизации, эффективность выполнения была значительно улучшена.
Однако каждый раз, когда вы используете getInstance() в программе, вам приходится проходить слой синхронизированной блокировки, что неизбежно увеличивает временные затраты метода getInstance(), а также может привести к блокировке. мы представляем нижеЗаблокированная версия с двойной проверкойОн существует для решения этой проблемы.
2.3 Ленивый человек (заблокированная версия с двойной проверкой)
Используя блокировку с двойной проверкой, сначала проверьте, был ли создан экземпляр, если нет, «только» синхронизируйте. Таким образом, есть только одна синхронизация, а это именно то, что нам нужно.
public class Singleton {
//volatile保证,当uniqueInstance变量被初始化成Singleton实例时,多个线程可以正确处理uniqueInstance变量
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getInstance() {
//检查实例,如果不存在,就进入同步代码块
if (uniqueInstance == null) {
//只有第一次才彻底执行这里的代码
synchronized(Singleton.class) {
//进入同步代码块后,再检查一次,如果仍是null,才创建实例
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
Очевидно, что этот метод может значительно сократить время, затрачиваемое на getInstance(), по сравнению с методом, использующим ключевое слово synchronized.
Мы использовали ключевое слово volatile выше, чтобы обеспечить видимость данных.Содержание ключевого слова volatile см. в моей статье:«Многопоточное обучение Java (3) изменчивое ключевое слово»: blog.CSDN.net/QQ_34337272…
Уведомление:Версия блокировки с двойной проверкой не работает с Java 1.4 и более ранними версиями. В Java 1.4 и более ранних версиях многие JVM-реализации ключевого слова volatile приводили к сбою блокировки с двойной проверкой.
2.4 Стиль ленивого человека (стиль регистрации/стиль статического внутреннего класса)
Статически реализованные синглтоны загружаются лениво и потокобезопасны.
Только при явном вызове метода getInstance класс SingletonHolder будет явно загружен, тем самым будет создан экземпляр экземпляра (только при первом использовании экземпляра этого синглтона и не будет проблем с безопасностью потоков).
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
2.5 Голодный китайский стиль (метод подсчета)
Эта реализация не получила широкого распространения, но это лучший способ реализации одноэлементного шаблона.Он более лаконичен, автоматически поддерживает механизм сериализации и определенно предотвращает создание нескольких экземпляров.(Если класс singleton реализует интерфейс Serializable, каждая десериализация будет создавать новый объект экземпляра по умолчанию. Чтобы узнать о проблемах singleton и сериализации, вы можете прочитать эту статью.«Вещи о синглтонах и сериализации»), который также рекомендуется авторами книги «Эффективная Java» и «Ява и шаблоны».
public enum Singleton {
//定义一个枚举的元素,它就是 Singleton 的一个实例
INSTANCE;
public void doSomeThing() {
System.out.println("枚举方法实现单例");
}
}
Инструкции:
public class ESTest {
public static void main(String[] args) {
Singleton singleton = Singleton.INSTANCE;
singleton.doSomeThing();//output:枚举方法实现单例
}
}
«Эффективное издание Java на китайском языке, второе издание»
Этот метод аналогичен по функциям общедоступному методу, но он более лаконичен, предоставляет бесплатный механизм сериализации и полностью предотвращает создание нескольких экземпляров даже перед лицом сложных атак сериализации или отражения. Хотя этот подход не получил широкого распространения, одноэлементные перечисляемые типы стали лучшим способом реализации Singleton. —— «Эффективное издание Java на китайском языке, второе издание»
Java и шаблоны
В статье «Java и шаблоны» автор написал, что более лаконично использовать перечисление для реализации управления одним экземпляром и предоставляет бесплатный механизм сериализации, а JVM принципиально гарантирует абсолютное предотвращение множественных экземпляров. эффективный и безопасный способ реализации синглетонов.
2.6 Резюме
В основном мы представили следующие способы реализации одноэлементного шаблона:
- Голодный путь (поточно-безопасный)
- Ленивые (не потокобезопасные и синхронизированные потокобезопасные версии ключевых слов)
- Lazy (версия блокировки с двойной проверкой)
- Стиль ленивого человека (стиль регистрации/стиль статического внутреннего класса)
- Голодный китайский стиль (метод перечисления)
Ссылаться на:
«Шаблоны проектирования Head First»
«Эффективное издание Java на китайском языке, второе издание»
[Java] Шаблоны проектирования: глубокое понимание шаблона Singleton
Я Snailclimb, новичок, планирующий стать архитектором в ближайшие 5 лет. Добро пожаловать в мой публичный аккаунт WeChat: "Руководство по прохождению собеседования на Java"(Теплый публичный аккаунт WeChat, с нетерпением жду вместе с вами прогресса ~~~ настаивайте на оригинальности, делитесь красивыми текстами и делитесь различными учебными ресурсами Java):