Как да направите перфектния Singleton?

Моделите на дизайна са популярни сред разработчиците на софтуер. Дизайнът на модела е добре описано решение на често срещан софтуер. Singleton е един от моделите на Creative Creative Design в Java.

Каква е целта на Singleton?

Целта на класа Singleton е да контролира създаването на обекти, ограничавайки броя на обектите само до един. Сингълът позволява само една входна точка за създаване на новата инстанция на класа.

Тъй като има само един екземпляр Singleton, всякакви екземплярни полета на Singleton ще се появяват само веднъж на клас, точно както статичните полета. Singletons често са полезни, когато трябва да контролирате ресурсите, като връзки към база данни или сокети.

Изглежда, че това е прост модел на дизайна, но когато става въпрос за внедряването, той идва с много опасения за изпълнение. Реализацията на Singleton модел винаги е била спорна тема сред разработчиците. Тук ще обсъдите как да създадете клас Singleton, който изпълнява целта си:

Ограничете създаването на клас и гарантира, че във виртуалната машина java съществува само един екземпляр от класа.

Нека създадем Singleton клас в java и да го тестваме в различни условия.

Създайте клас Singleton

За да приложите класа Singleton, най-простият начин е да направите конструктора на класа като частен. Има два подхода за инициализация.

1. Ефектна инициализация:

При нетърпеливата инициализация, инстанцията на Singleton Class се създава по време на зареждане на клас, това е най-лесният метод за създаване на клас Singleton.

Като направите конструктора като частен, вие не позволявате на друг клас да създаде нов екземпляр от класа, който искате да създадете Singleton. Вместо това създавате един публичен статичен метод (често име като getInstance ()), за да предоставите единната входна точка, за да създадете новия екземпляр на класа.

Този подход има един недостатък. Тук например се създава, въпреки че клиентското приложение може да не го използва. Това може да е сериозен проблем, ако вашето
Singleton клас при създаване на връзка с база данни или създаване на сокет. Това може да причини проблем с изтичането на паметта. Решението е да се създаде новата инстанция на класа, когато е необходимо. Това може да бъде постигнато чрез метода на Lazy Initialization.

2. Мързелива инициализация:

Противно на Eager инициализацията, тук ще инициализирате нов екземпляр от класа в метода getInstance (). Този метод ще провери дали вече има създаден екземпляр от този клас? Ако да, тогава нашият метод (getInstance ()) ще върне този стар екземпляр, а ако не, тогава създава нов екземпляр от класа Singleton в JVM и връща този екземпляр. Този подход се нарича инициализация на Lazy.

Всички знаем, че в Java, ако двата обекта са еднакви тогава, техният хеш ключ трябва да е равен. Нека да тестваме това. Ако горният Singleton е приложен правилно, по-долу код трябва да върне същия хеш ключ.

По-долу е изходният дневник с хеш код на двата екземпляра.

И двамата имат еднакъв хеш.

Можете да видите, че и двете инстанции имат един и същ хеш код. Така че това означава, че горният код ще направи перфектния Singleton. Право ???? Не.

Направете Singleton отражение доказателство

В горния клас Singleton, с помощта на отражение можете да създадете повече от един екземпляр. Ако не знаете какво е API на Java Reflection, Java Reflection е процес на разглеждане или промяна на поведението на даден клас на изпълнение по време на изпълнение.

Можете да направите новия екземпляр от класа Singleton, като промените видимостта на конструктора като публична по време на изпълнение и създадете нов екземпляр, използвайки този конструктор. Пуснете кода по-долу и вижте дали оцелява нашия клас Singleton?

Ето изхода на хеш кодовете и на двата случая.

Тестово отражение

И двата случая имат различен хеш код. Това ясно показва, че клас Singleton не успя да проведе този тест.

Решение:

За да предотвратите повреда на Singleton, докато се дължи на отражение, трябва да хвърлите изключение за изпълнение в конструктор, ако конструкторът вече е инициализиран и някой клас да го инициализира отново. Нека актуализираме SingletonClass.java.

Направете Singleton нишка безопасна

Ако две нишки се опитват да инициализират класа Singleton почти едновременно, какво се случва? Нека тестваме по-долу код, в който две нишки се създават почти едновременно и те викат getInstance ().

Ако стартирате този код много пъти, ще видите понякога и двете нишки създават различни екземпляри.

Това означава, че вашият клас Singleton не е безопасен за конци. И двете нишки извикват метод getInstance () едновременно, условието sSoleInstance == null ще се върне и за двете нишки. Така ще бъдат създадени два различни екземпляра от един и същи клас. Това ще наруши принципа на сингъл.

Решение:

1. Направете getInstance () синхронизиран:

Нека синхронизираме метода getInstance ().

Докато сте направили синхронизирания си клас getInstance (), втората нишка ще трябва да изчака, докато методът getInstance () приключи за първата нишка. По този начин можем да постигнем безопасност на резбата.

Но има някои минуси при използването на този подход:

  • Бавно изпълнение поради заключване над главата.
  • Ненужна синхронизация, която не се изисква, след като променливата на инстанцията се инициализира.

2. Метод за двойно заключване на проверка:

Можете да преодолеете този проблем, ако използвате метода за двойно заключване, за да създадете Singleton.

В този случай ще направите класа Singleton в синхронизирания блок, ако инстанцията е нула. Така че синхронизираният блок ще бъде изпълнен само когато sSoleInstance е нулева и ще предотврати ненужното синхронизиране, след като променливата на инстанцията се инициализира.

3. Използвайте летливата ключова дума:

На повърхността, този метод изглежда перфектен, тъй като трябва само да платите цена за синхронизиран блок един път, но той все още е счупен, докато не направите sSoleInstance променлива променлива.

Без променлив модификатор е възможно друга нишка в Java да види наполовина инициализирано състояние на променлива sSoleInstance, но с летливата променлива, гарантираща случване преди връзката, цялото записване ще се случи на летливата sSoleInstance преди всяко четене на променлива sSoleInstance.

Сега над класа Singleton е безопасен конци. Правенето на Singleton в безопасност е особено необходимо в среда с много нишки на приложения, като в приложенията за Android.

Направете Singleton безопасен от сериализация

Понякога в разпределените системи е необходимо да внедрите Serializable интерфейс в Singleton клас. По този начин можете да съхраните състоянието му във файловата система и да го извлечете в по-късен момент.

Нека да тестваме сингълтон клас дали поддържа единичен екземпляр след сериализируеми и десериализируеми операции?

Можете да видите, че хеш кодът и на двата екземпляра е различен. Това очевидно нарушава принципа на сингъл. Проблемът с горния сериализиран клас Singleton е, че всеки път, когато го десериализираме, той ще създаде нов екземпляр от класа.

За да предотвратите създаването на друг екземпляр, трябва да осигурите прилагането на метода readResolve (). readResolve () замества обекта, който се чете от потока. Това гарантира, че никой не може да създаде друг екземпляр чрез сериализиране и десериализиране на сингълтона.

Заключение:

В края на статията можете да направите класа си Singleton клас, който е конци, размисъл и сериализация. Този сингълтън все още не е перфектният сингълтън. Можете да нарушите принципа на Singleton, като създадете повече от един екземпляр от класа Singleton, като използвате клониране или използване на многокласни товарачи. Но за повечето приложения, изпълнението на Singleton ще работи перфектно.

https://paypal.me/kpatel2106?locale.x=en_GB

Ако това ви е харесало, щракнете върху по-долу, така че другите хора да виждат това тук на Medium. Ако имате въпроси или предложения, не се колебайте да ме ударите в Twitter.