
Ce este un singleton în Java?
Singleton este unul dintre cele mai simple modele de design la nivel de clasă. Uneori oamenii spun „această clasă este singleton”, ceea ce înseamnă că clasa implementează modelul de design singleton. Uneori este necesar să scriem o clasă în care limităm instanțiarea la un singur obiect. De exemplu, o clasă responsabilă pentru înregistrarea sau conectarea la un baza de date. Modelul de design singleton descrie cum putem realiza acest lucru. Un model singleton este un model de design care face două lucruri:-
Acesta garantează că va exista o singură instanță a clasei.
-
Oferă un singur punct de acces global la acea instanță.
-
Un constructor privat. Acest lucru limitează capacitatea de a crea obiecte ale clasei în afara clasei în sine.
-
O metodă publică statică care returnează instanța clasei. Această metodă se numește getInstance . Acesta este punctul de acces global la instanța clasei.
Opțiuni de implementare
Modelul de design singleton este aplicat în diferite moduri. Fiecare opțiune este bună și rea în felul ei. Ca întotdeauna, nu există o opțiune perfectă aici, dar ar trebui să ne străduim pentru una. În primul rând, să decidem ce este bun și rău și ce măsurători afectează modul în care evaluăm diferitele implementări ale modelului de proiectare. Să începem cu binele. Iată factorii care fac o implementare mai suculentă și mai atrăgătoare:-
Inițializare leneșă: instanța nu este creată până când este necesară.
-
Cod simplu și transparent: această metrică, desigur, este subiectivă, dar este importantă.
-
Siguranța firelor: funcționare corectă într-un mediu cu mai multe fire.
-
Performanță ridicată într-un mediu cu mai multe fire de execuție: blocarea firelor de execuție este mică sau deloc atunci când partajați o resursă.
-
Fără inițializare leneșă: când se încarcă clasa când pornește aplicația, indiferent dacă este sau nu necesară (paradoxal, în lumea IT este mai bine să fii leneș)
-
Cod complex și greu de citit. Această măsurătoare este, de asemenea, subiectivă. Dacă ochii tăi încep să sângereze, vom presupune că implementarea nu este cea mai bună.
-
Lipsa siguranței firului. Cu alte cuvinte, „pericol de fir”. Funcționare incorectă într-un mediu cu mai multe fire.
-
Performanță slabă într-un mediu cu mai multe fire de execuție: firele de execuție se blochează reciproc tot timpul sau des atunci când partajează o resursă.
Cod
Acum suntem gata să luăm în considerare diverse opțiuni de implementare și să indicăm argumentele pro și contra:Simplu
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
Cea mai simplă implementare. Pro:
-
Cod simplu și transparent
-
Siguranța firului
-
Performanță ridicată într-un mediu cu mai multe fire
- Fără inițializare leneșă.
Inițializare leneșă
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Pro:
-
Inițializare leneșă.
-
Nu este sigur pentru fire
Acces sincronizat
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Pro:
-
Inițializare leneșă.
-
Siguranța firului
-
Performanță slabă cu mai multe fire
Încuiere dublu verificată
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {
}
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized (Singleton.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
Pro:
-
Inițializare leneșă.
-
Siguranța firului
-
Performanță ridicată într-un mediu cu mai multe fire
-
Nu este acceptat în versiunile anterioare de Java sub 1.5 (utilizarea cuvântului cheie volatil este fixată de la versiunea 1.5)
Titularul clasei
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
public static final Singleton HOLDER_INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.HOLDER_INSTANCE;
}
}
Pro:
-
Inițializare leneșă.
-
Siguranța firului.
-
Performanță ridicată într-un mediu cu mai multe fire.
-
Funcționarea corectă necesită o garanție că obiectul singleton este inițializat fără erori. În caz contrar, primul apel la metoda getInstance va avea ca rezultat un ExceptionInInitializerError , iar toate apelurile ulterioare vor produce un NoClassDefFoundError .
Implementarea | Inițializare leneșă | Siguranța firului | Performanță cu mai multe fire | Când să folosiți? |
---|---|---|---|---|
Simplu | - | + | Rapid | Nu. Sau, eventual, atunci când inițializarea leneșă nu este importantă. Dar niciodată nu ar fi mai bine. |
Inițializare leneșă | + | - | Nu se aplică | Întotdeauna când multithreading nu este necesar |
Acces sincronizat | + | + | Încet | Nu. Sau, eventual, atunci când performanța multithreaded nu contează. Dar niciodată nu ar fi mai bine. |
Încuiere dublu verificată | + | + | Rapid | În cazuri rare, când trebuie să gestionați excepții la crearea singleton-ului (când singletonul deținătorului clasei nu este aplicabil) |
Titularul clasei | + | + | Rapid | Ori de câte ori este nevoie de multithreading și există garanția că obiectul singleton va fi creat fără probleme. |
Avantaje și dezavantaje ale modelului singleton
În general, un singleton face exact ceea ce se așteaptă de la el:-
Acesta garantează că va exista o singură instanță a clasei.
-
Oferă un singur punct de acces global la acea instanță.
-
Un singleton încalcă principiul responsabilității unice: pe lângă sarcinile sale directe, clasa singleton controlează și numărul de instanțe.
-
Dependența unei clase obișnuite de un singleton nu este vizibilă în contractul public al clasei.
-
Variabilele globale sunt proaste. În cele din urmă, un singleton se transformă într-o variabilă globală puternică.
-
Prezența unui singleton reduce capacitatea de testare a aplicației în ansamblu și a claselor care folosesc singletonul în special.
GO TO FULL VERSION