Автор оригинала: Pankaj Kumar.
Синглтон-один из наиболее широко используемых шаблонов творческого проектирования для ограничения объектов, создаваемых приложениями. Если вы используете его в многопоточной среде, то потокобезопасность одноэлементного класса очень важна.
В реальных приложениях ресурсы, такие как подключения к базам данных или Корпоративные информационные системы (EIS), ограничены, и их следует использовать разумно, чтобы избежать любого дефицита ресурсов.
Для достижения этой цели мы можем реализовать шаблон одноэлементного проектирования . Мы можем создать класс-оболочку для ресурса и ограничить количество объектов, созданных во время выполнения, одним.
Потокобезопасный синглтон в Java
В общем, мы выполняем следующие действия, чтобы создать одноэлементный класс:
- Создайте закрытый конструктор , чтобы избежать создания любого нового объекта с помощью нового оператора.
- Объявите частный статический экземпляр того же класса.
- Предоставьте общедоступный статический метод, который вернет переменную экземпляра одноэлементного класса. Если переменная не инициализирована, то инициализируйте ее или просто верните переменную экземпляра.
Используя описанные выше шаги, я создал одноэлементный класс, который выглядит следующим образом.
Используя описанные выше шаги, я создал одноэлементный класс, который выглядит следующим образом.
package com.journaldev.designpatterns; public class ASingleton { private static ASingleton instance = null; private ASingleton() { } public static ASingleton getInstance() { if (instance == null) { instance = new ASingleton(); } return instance; } }
В приведенном выше коде метод getInstance() не является потокобезопасным.
Несколько потоков могут получить к нему доступ одновременно. Для первых нескольких потоков, когда переменная экземпляра не инициализирована, несколько потоков могут войти в цикл if и создать несколько экземпляров. Это нарушит вашу одноэлементную реализацию.
Как добиться потокобезопасности в одноэлементном классе?
Существует три способа, с помощью которых мы можем обеспечить безопасность потоков.
- Создайте переменную экземпляра во время загрузки класса.
- Потокобезопасность без синхронизации
- Простота в реализации
- Раннее создание ресурса, который может не использоваться в приложении.
- Клиентское приложение не может передать никаких аргументов, поэтому мы не можем использовать его повторно. Например, наличие универсального одноэлементного класса для подключения к базе данных, в котором клиентское приложение предоставляет свойства сервера базы данных.
- Синхронизируйте метод getInstance () .
- Безопасность резьбы гарантируется.
- Клиентское приложение может передавать параметры
- Достигнута ленивая инициализация
- Низкая производительность из-за накладных расходов на блокировку.
- Ненужная синхронизация, которая не требуется после инициализации переменной экземпляра.
- Используйте синхронизированный блок внутри цикла if и переменную volatile
- Безопасность резьбы гарантируется
- Клиентское приложение может передавать аргументы
- Достигнута ленивая инициализация
- Накладные расходы на синхронизацию минимальны и применимы только для первых нескольких потоков, когда переменная равна нулю.
- Дополнительное условие if
Плюсы :
Минусы :
Плюсы :
Минусы :
Плюсы :
Минусы :
Рассматривая все три способа обеспечения потокобезопасности, я думаю, что третий-лучший вариант. В этом случае измененный класс будет выглядеть следующим образом:
package com.journaldev.designpatterns; public class ASingleton { private static volatile ASingleton instance; private static Object mutex = new Object(); private ASingleton() { } public static ASingleton getInstance() { ASingleton result = instance; if (result == null) { synchronized (mutex) { result = instance; if (result == null) instance = result = new ASingleton(); } } return result; } }
Локальная переменная результат
кажется ненужной. Но он предназначен для повышения производительности нашего кода. В тех случаях, когда экземпляр уже инициализирован (большую часть времени), доступ к полю volatile осуществляется только один раз (из-за “возвращаемого результата;” вместо “возвращаемого экземпляра;”). Это может повысить общую производительность метода на целых 25 процентов.
Если вы считаете, что есть лучшие способы достичь этого или если потокобезопасность нарушена в приведенной выше реализации, пожалуйста, прокомментируйте и поделитесь ею со всеми нами.
Бонусный Совет
Строка-не очень хороший кандидат для использования с синхронизированным ключевым словом. Это потому, что они хранятся в пуле строк, и мы не хотим блокировать строку, которая может использоваться другим фрагментом кода. Поэтому я использую объектную переменную. Узнайте больше о синхронизации и безопасности потоков в java .