Jak vyrobit perfektní Singleton?

Designové vzory jsou populární mezi vývojáři softwaru. Designový vzor je dobře popsané řešení běžného softwarového problému. Singleton je jedním z kreativních návrhových vzorů v Javě.

Jaký je účel Singletonu?

Účelem třídy Singleton je řídit vytváření objektů a omezit počet objektů pouze na jeden. Singleton umožňuje novou instanci třídy vytvořit pouze jedním vstupním bodem.

Protože existuje pouze jedna instance Singleton, všechna pole instance Singleton se objeví pouze jednou za třídu, stejně jako statická pole. Singletons jsou často užitečné tam, kde musíte ovládat zdroje, jako jsou připojení k databázi nebo sokety.

Zdá se, že jde o jednoduchý návrhový vzor, ​​ale pokud jde o implementaci, přichází se spoustou implementačních problémů. Implementace Singletonova vzoru byla vždy vývojovým tématem mezi vývojáři. Zde budete diskutovat o tom, jak vytvořit třídu Singleton, která splňuje svůj účel:

Omezte instanci třídy a zajistěte, aby ve virtuálním stroji java existovala pouze jedna instance třídy.

Vytvořme třídu Singleton v javě a vyzkoušejte ji v různých podmínkách.

Vytvořte třídu Singleton

Pro implementaci třídy Singleton je nejjednodušší způsob, jak postavit konstruktéra třídy jako soukromý. Pro inicializaci existují dva přístupy.

1. Inicializace spouštění:

V dychtivé inicializaci je instance třídy Singleton vytvořena v době načítání třídy, což je nejjednodušší metoda vytvoření třídy Singleton.

Nastavením konstruktoru jako soukromého neumožníte jiné třídě vytvořit novou instanci třídy, kterou chcete vytvořit Singleton. Místo toho vytváříte jednu veřejnou statickou metodu (obvykle pojmenovanou jako pro getInstance ()), která poskytuje jediný vstupní bod k vytvoření nové instance třídy.

Tento přístup má jednu nevýhodu. Zde se vytvoří instance, i když ji klientská aplikace nemusí používat. To by mohl být značný problém, pokud váš
Třída Singleton při vytváření databázového připojení nebo vytváření soketu. To může způsobit problém s nevracením paměti. Řešením je v případě potřeby vytvořit novou instanci třídy. Toho lze dosáhnout metodou Lazy Initialization.

2. Líná inicializace:

Oproti inicializaci Eageru zde inicializujete novou instanci třídy metodou getInstance (), kterou vlastní. Tato metoda zkontroluje, zda již existuje nějaká instance této třídy? Pokud ano, pak naše metoda (getInstance ()) vrátí tu starou instanci a pokud ne, vytvoří novou instanci třídy singleton v JVM a vrátí tuto instanci. Tento přístup se nazývá inicializace Lazy.

Všichni víme, že pokud jsou v Javě dva objekty stejné, jejich hashovací klíč musí být stejný. Zkusme to. Pokud je výše uvedený Singleton správně implementován, měl by pod kódem vrátit stejný hash klíč.

Níže je výstupní protokol s hash kódem obou instancí.

Oba mají stejný hash.

Můžete vidět, že obě instance mají stejný hashovací kód. To znamená, že výše uvedený kód vytvoří perfektní Singleton. Že jo???? Ne.

Udělejte Singleton odraz jako důkaz

Ve výše uvedené třídě Singleton můžete pomocí reflexe vytvořit více než jednu instanci. Pokud nevíte, co je to Java Reflection API, Java Reflection je proces zkoumání nebo modifikace běhového chování třídy za běhu.

Můžete vytvořit novou instanci třídy Singleton změnou viditelnosti konstruktoru jako veřejné za běhu a pomocí této konstruktory vytvořit novou instanci. Spusťte níže uvedený kód a uvidíte, že naše třída Singleton přežije?

Zde je výstup hash kódů obou instancí.

Testování odrazu

Obě instance mají jiný hashovací kód. To jasně ukazuje, že třída Singleton tento test selhala.

Řešení:

Chcete-li zabránit selhání Singleton, zatímco kvůli odrazu, musíte v konstruktoru vyvolat výjimku run-time, pokud je konstruktor již inicializován a některá třída jej znovu inicializuje. Aktualizujme SingletonClass.java.

Zajistěte vlákno Singleton bezpečné

Pokud se dvě vlákna pokusí inicializovat třídu Singleton téměř ve stejnou dobu, co se stane? Vyzkoušejte níže kód, ve kterém jsou dvě vlákna vytvořena téměř současně a volají getInstance ().

Pokud spustíte tento kód mnohokrát, uvidíte někdy obě vlákna vytvoří různé instance.

To znamená, že vaše třída Singleton není bezpečná pro vlákno. Oba podprocesy vyvolávají metodu getInstance () současně, podmínka sSoleInstance == null se vrátí pro obě vlákna. Budou tedy vytvořeny dva různé instance stejné třídy. Tím se poruší princip singletonu.

Řešení:

1. Proveďte synchronizaci getInstance ():

Udělejme synchronizaci metody getInstance ().

Po synchronizaci třídy getInstance () bude druhé vlákno muset čekat, dokud nebude pro první vlákno dokončena metoda getInstance (). Tímto způsobem můžeme dosáhnout bezpečnosti závitu.

Existuje však několik nevýhod používání tohoto přístupu:

  • Pomalý výkon kvůli zamykání režie.
  • Po inicializaci proměnné instance není nutná zbytečná synchronizace.

2. Způsob zamykání s dvojitou kontrolou:

Tento problém můžete překonat, pokud k vytvoření Singletonu použijete metodu zamykání Double check.

V tomto případě vytvoříte třídu Singleton v synchronizovaném bloku, pokud je instance nulová. Synchronizovaný blok bude tedy proveden pouze v případě, že je sSoleInstance null a po inicializaci proměnné instance zabrání zbytečné synchronizaci.

3. Použijte volatilní klíčové slovo:

Tato metoda vypadá na povrchu dokonale, protože za synchronizovaný blok musíte zaplatit pouze jednou, ale stále byla porušena, dokud proměnnou sSoleInstance nestabilní.

Bez volatile modifikátoru je možné, aby další vlákno v Javě vidělo polovinu inicializovaného stavu proměnné sSoleInstance, ale s volatile proměnnou zaručující vztah před a dříve se vše zapíše na volatile sSoleInstance před jakýmkoli přečtením proměnné sSoleInstance.

Nyní je třída Singleton bezpečná pro vlákno. Zajištění bezpečnosti vlákna Singleton je vyžadováno zejména v aplikačním prostředí s více vlákny, například v aplikacích pro Android.

Zajistěte Singleton v bezpečí před serializací

Někdy v distribuovaných systémech musíte implementovat rozhraní Serializable ve třídě Singleton. Tímto způsobem můžete uložit jeho stav do systému souborů a načíst jej později.

Vyzkoušejte singletonovou třídu, zda udržuje jednu instanci po serializovatelných a deserializovatelných operacích?

Můžete vidět, že hash kód obou instancí je jiný. To jasně porušuje princip singletonu. Problém s výše serializovanou třídou singleton je v tom, že kdykoli ji deserializujeme, vytvoří novou instanci třídy.

Chcete-li zabránit vytvoření jiné instance, musíte zajistit implementaci metody readResolve (). readResolve () nahrazuje objekt načtený ze streamu. To zajišťuje, že nikdo nemůže vytvořit další instanci serializací a deserializací singletonu.

Závěr:

Na konci článku můžete svou třídu učinit třídou Singleton, která je bezpečná pro vlákna, odrazy a serializaci. Tento Singleton stále není dokonalý Singleton. Princip Singleton můžete porušit vytvořením více než jedné instance třídy Singleton pomocí klonování nebo pomocí zavaděče více tříd. Ale pro většinu aplikací bude výše uvedená implementace Singletonu fungovat perfektně.

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

Pokud se vám to líbilo, klikněte níže na , aby se ostatním lidem zobrazilo toto na médiu. Pokud máte nějaké dotazy nebo návrhy, neváhejte mě zasáhnout na Twitteru.