Hva er en singleton i Java?
Singleton er et av de enkleste designmønstrene på klassenivå. Noen ganger sier folk "denne klassen er singleton", som betyr at klassen implementerer singleton-designmønsteret. Noen ganger er det nødvendig å skrive en klasse der vi begrenser instansiering til et enkelt objekt. For eksempel en klasse som er ansvarlig for å logge eller koble til en database. Singleton-designmønsteret beskriver hvordan vi kan oppnå dette. En singleton er et designmønster som gjør to ting:-
Det garanterer at det bare vil være én forekomst av klassen.
-
Det gir et enkelt punkt med global tilgang til den forekomsten.
-
En privat konstruktør. Dette begrenser muligheten til å lage objekter av klassen utenfor selve klassen.
-
En offentlig statisk metode som returnerer forekomsten av klassen. Denne metoden kalles getInstance . Dette er poenget med global tilgang til klasseforekomsten.
Implementeringsmuligheter
Singleton-designmønsteret brukes på forskjellige måter. Hvert alternativ er bra og dårlig på sin egen måte. Som alltid er det ikke noe perfekt alternativ her, men vi bør strebe etter et. Først av alt, la oss bestemme hva som er bra og dårlig, og hvilke beregninger som påvirker hvordan vi vurderer de ulike implementeringene av designmønsteret. La oss starte med det gode. Her er faktorer som gjør en implementering mer saftig og tiltalende:-
Lazy initialisering: forekomsten opprettes ikke før den er nødvendig.
-
Enkel og gjennomsiktig kode: denne beregningen er selvfølgelig subjektiv, men den er viktig.
-
Gjengesikkerhet: korrekt drift i et flertrådsmiljø.
-
Høy ytelse i et flertrådsmiljø: liten eller ingen trådblokkering når du deler en ressurs.
-
Ingen lat initialisering: når klassen lastes når applikasjonen starter, uavhengig av om den er nødvendig eller ikke (paradoksalt nok, i IT-verdenen er det bedre å være lat)
-
Kompleks og vanskelig å lese kode. Denne beregningen er også subjektiv. Hvis øynene dine begynner å blø, antar vi at implementeringen ikke er den beste.
-
Mangel på trådsikkerhet. Med andre ord "trådfare". Feil drift i et flertrådsmiljø.
-
Dårlig ytelse i et flertrådsmiljø: tråder blokkerer hverandre hele tiden eller ofte når de deler en ressurs.
Kode
Nå er vi klare til å vurdere ulike implementeringsalternativer og angi fordeler og ulemper:Enkel
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
Den enkleste implementeringen. Fordeler:
-
Enkel og gjennomsiktig kode
-
Trådsikkerhet
-
Høy ytelse i et flertrådsmiljø
- Ingen lat initialisering.
Lat initialisering
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Fordeler:
-
Lat initialisering.
-
Ikke trådsikker
Synkronisert tilgang
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Fordeler:
-
Lat initialisering.
-
Trådsikkerhet
-
Dårlig multithreaded ytelse
Dobbeltsjekket låsing
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;
}
}
Fordeler:
-
Lat initialisering.
-
Trådsikkerhet
-
Høy ytelse i et flertrådsmiljø
-
Støttes ikke i tidligere versjoner av Java under 1.5 (bruken av flyktige nøkkelord er løst siden 1.5-versjonen)
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;
}
}
Fordeler:
-
Lat initialisering.
-
Trådsikkerhet.
-
Høy ytelse i et flertrådsmiljø.
-
Riktig drift krever en garanti for at singleton- objektet initialiseres uten feil. Ellers vil det første kallet til getInstance -metoden resultere i en ExceptionInInitializerError , og alle påfølgende anrop vil produsere en NoClassDefFoundError .
Gjennomføring | Lat initialisering | Trådsikkerhet | Multithreaded ytelse | Når skal du bruke? |
---|---|---|---|---|
Enkel | - | + | Fort | Aldri. Eller muligens når lat initialisering ikke er viktig. Men ville aldri vært bedre. |
Lat initialisering | + | - | Ikke aktuelt | Alltid når flertråding ikke er nødvendig |
Synkronisert tilgang | + | + | Langsom | Aldri. Eller muligens når multithreaded ytelse ikke spiller noen rolle. Men ville aldri vært bedre. |
Dobbeltsjekket låsing | + | + | Fort | I sjeldne tilfeller når du trenger å håndtere unntak når du oppretter singleton (når klasseholderen singleton ikke er aktuelt) |
Klasseholder | + | + | Fort | Når multithreading er nødvendig og det er en garanti for at singleton-objektet vil bli opprettet uten problemer. |
Fordeler og ulemper med singleton-mønsteret
Generelt gjør en singleton akkurat det som forventes av den:-
Det garanterer at det bare vil være én forekomst av klassen.
-
Det gir et enkelt punkt med global tilgang til den forekomsten.
-
En singleton bryter med enkeltansvarsprinsippet: i tillegg til sine direkte plikter kontrollerer singleton-klassen også antall instanser.
-
En vanlig klasses avhengighet av en singleton er ikke synlig i klassens offentlige kontrakt.
-
Globale variabler er dårlige. Til syvende og sist blir en singleton til en heftig global variabel.
-
Tilstedeværelsen av en singleton reduserer testbarheten til applikasjonen som helhet og klassene som bruker singletonen spesielt.
GO TO FULL VERSION