CodeGym /Java blog /Tilfældig /Java Singleton klasse
John Squirrels
Niveau
San Francisco

Java Singleton klasse

Udgivet i gruppen
Hej! I dag vil vi dykke ned i detaljerne i forskellige designmønstre, begyndende med Java Singleton-mønsteret. Lad os gennemgå: hvad ved vi om designmønstre generelt? Designmønstre er bedste praksis, som vi kan anvende til at løse en række kendte problemer. Designmønstre er generelt ikke bundet til noget programmeringssprog. Tænk på dem som et sæt anbefalinger, der hjælper dig med at undgå fejl og undgå at genopfinde hjulet.Designmønstre: Singleton - 1

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:
  1. Det garanterer, at der kun vil være én forekomst af klassen.

  2. Det giver et enkelt punkt med global adgang til den instans.

Derfor er der to funktioner, der er karakteristiske for næsten enhver implementering af singleton-mønsteret:
  1. En privat konstruktør. Dette begrænser muligheden for at skabe klassens objekter uden for selve klassen.

  2. 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.

Nu ulemperne. Vi oplister faktorer, der sætter en implementering i et dårligt lys:
  • 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ø

Ulemper:
  • Ingen doven initialisering.
I et forsøg på at rette op på den tidligere mangel får vi implementering nummer to:

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.

Ulemper:
  • Ikke trådsikker

Denne implementering er interessant. Vi kan initialisere dovent, men vi har mistet trådsikkerheden. Ingen bekymringer - vi synkroniserer alt i implementering nummer tre.

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

Ulemper:
  • Dårlig multithreaded ydeevne

Fremragende! I implementering nummer tre genopretter vi trådsikkerheden! Selvfølgelig er det langsomt... Nu er getInstance- metoden synkroniseret, så den kan udføres af kun én tråd ad gangen. I stedet for at synkronisere hele metoden, behøver vi faktisk kun at synkronisere den del af den, der initialiserer den nye instans. Men vi kan ikke bare bruge en synkroniseret blok til at indpakke den del, der er ansvarlig for at oprette den nye instans. At gøre det ville ikke sikre trådsikkerheden. Det hele er lidt mere kompliceret. Korrekt synkronisering kan ses nedenfor:

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ø

Ulemper:
  • Ikke understøttet i tidligere versioner af Java under 1.5 (brugen af ​​flygtige søgeord er rettet siden 1.5-versionen)

Bemærk, at for at denne implementeringsmulighed skal fungere korrekt, skal en af ​​to betingelser være opfyldt. Variablen INSTANCE skal enten være endelig eller flygtig . Den sidste implementering, som vi vil diskutere i dag, er klasseholderen singleton .

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ø.

Ulemper:
  • 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 .

Denne implementering er næsten perfekt. Den er doven, og trådsikker og hurtig. Men det har en nuance, som forklaret i listen over ulemper. Sammenligning af forskellige implementeringer af singleton-mønsteret:
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:
  1. Det garanterer, at der kun vil være én forekomst af klassen.

  2. Det giver et enkelt punkt med global adgang til den instans.

Dette mønster har dog mangler:
  1. En singleton overtræder princippet om enkelt ansvar: Ud over sine direkte pligter kontrollerer singleton-klassen også antallet af instanser.

  2. En almindelig klasses afhængighed af en singleton er ikke synlig i klassens offentlige kontrakt.

  3. Globale variabler er dårlige. I sidste ende bliver en singleton til en heftig global variabel.

  4. Tilstedeværelsen af ​​en singleton reducerer testbarheden af ​​applikationen som helhed og de klasser, der bruger singletonen i særdeleshed.

Og det er det! :) Vi har udforsket Java Singleton Class med dig. Nu, for resten af ​​dit liv, når du taler med dine programmørvenner, kan du ikke kun nævne, hvor godt mønsteret er, men også et par ord om, hvad der gør det dårligt. Held og lykke med at mestre denne nye viden.

Yderligere læsning:

Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION