
Hvad er en singleton i Java?
Singleton er et af de enkleste designmønstre på klasseniveau. Nogle gange siger folk "denne klasse er singleton", hvilket betyder, at klassen implementerer singleton-designmønsteret. Nogle gange er det nødvendigt at skrive en klasse, hvor vi begrænser instansiering til et enkelt objekt. For eksempel en klasse, der er ansvarlig for at logge eller oprette forbindelse til en database. Singleton-designmønsteret beskriver, hvordan vi kan opnå dette. En singleton er et designmønster, der gør to ting:-
Det garanterer, at der kun vil være én forekomst af klassen.
-
Det giver et enkelt punkt med global adgang til den instans.
-
En privat konstruktør. Dette begrænser muligheden for at skabe klassens objekter uden for selve klassen.
-
En offentlig statisk metode, der returnerer forekomsten af klassen. Denne metode kaldes getInstance . Dette er punktet for global adgang til klasseinstansen.
Implementeringsmuligheder
Singleton-designmønsteret anvendes på forskellige måder. Hver mulighed er god og dårlig på sin egen måde. Som altid er der ingen perfekt mulighed her, men vi bør stræbe efter en. Lad os først og fremmest beslutte, hvad der er godt og dårligt, og hvilke målinger, der påvirker, hvordan vi vurderer de forskellige implementeringer af designmønsteret. Lad os starte med det gode. Her er faktorer, der gør en implementering mere saftig og tiltalende:-
Doven initialisering: instansen oprettes ikke, før den er nødvendig.
-
Enkel og gennemsigtig kode: Denne metrik er selvfølgelig subjektiv, men den er vigtig.
-
Gevindsikkerhed: korrekt betjening i et flertrådet miljø.
-
Høj ydeevne i et miljø med flere tråde: ringe eller ingen trådblokering ved deling af en ressource.
-
Ingen doven initialisering: når klassen indlæses, når applikationen starter, uanset om den er nødvendig eller ej (paradoksalt nok er det i IT-verdenen bedre at være doven)
-
Kompleks og svær at læse kode. Denne metrik er også subjektiv. Hvis dine øjne begynder at bløde, antager vi, at implementeringen ikke er den bedste.
-
Manglende trådsikkerhed. Med andre ord "trådfare". Forkert betjening i et flertrådet miljø.
-
Dårlig ydeevne i et miljø med flere tråde: Tråde blokerer for hinanden hele tiden eller ofte, når de deler en ressource.
Kode
Nu er vi klar til at overveje forskellige implementeringsmuligheder og angive fordele og ulemper:Enkel
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
Den enkleste implementering. Fordele:
-
Enkel og gennemsigtig kode
-
Trådsikkerhed
-
Høj ydeevne i et flertrådet miljø
- Ingen doven initialisering.
Doven initialisering
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Fordele:
-
Doven initialisering.
-
Ikke trådsikker
Synkroniseret adgang
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Fordele:
-
Doven initialisering.
-
Trådsikkerhed
-
Dårlig multithreaded ydeevne
Dobbelttjekket låsning
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;
}
}
Fordele:
-
Doven initialisering.
-
Trådsikkerhed
-
Høj ydeevne i et flertrådet miljø
-
Ikke understøttet i tidligere versioner af Java under 1.5 (brugen af flygtige søgeord er rettet siden 1.5-versionen)
Klasseholder
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;
}
}
Fordele:
-
Doven initialisering.
-
Trådsikkerhed.
-
Høj ydeevne i et flertrådet miljø.
-
Korrekt betjening kræver en garanti for, at singleton- objektet initialiseres uden fejl. Ellers vil det første kald til getInstance- metoden resultere i en ExceptionInInitializerError , og alle efterfølgende kald vil producere en NoClassDefFoundError .
Implementering | Doven initialisering | Trådsikkerhed | Multithreaded ydeevne | Hvornår skal man bruge? |
---|---|---|---|---|
Enkel | - | + | Hurtig | Aldrig. Eller muligvis når doven initialisering ikke er vigtig. Men det ville aldrig være bedre. |
Doven initialisering | + | - | Ikke anvendelig | Altid når multithreading ikke er nødvendig |
Synkroniseret adgang | + | + | Langsom | Aldrig. Eller muligvis når multithreaded ydeevne ikke betyder noget. Men det ville aldrig være bedre. |
Dobbelttjekket låsning | + | + | Hurtig | I sjældne tilfælde, når du skal håndtere undtagelser, når du opretter singletonen (når klasseholderen singleton ikke er relevant) |
Klasseholder | + | + | Hurtig | Når der er behov for multithreading, og der er garanti for, at singleton-objektet bliver oprettet uden problemer. |
Fordele og ulemper ved singleton-mønsteret
Generelt gør en singleton præcis, hvad der forventes af den:-
Det garanterer, at der kun vil være én forekomst af klassen.
-
Det giver et enkelt punkt med global adgang til den instans.
-
En singleton overtræder princippet om enkelt ansvar: Ud over sine direkte pligter kontrollerer singleton-klassen også antallet af instanser.
-
En almindelig klasses afhængighed af en singleton er ikke synlig i klassens offentlige kontrakt.
-
Globale variabler er dårlige. I sidste ende bliver en singleton til en heftig global variabel.
-
Tilstedeværelsen af en singleton reducerer testbarheden af applikationen som helhed og de klasser, der bruger singletonen i særdeleshed.
GO TO FULL VERSION