CodeGym /Java blog /Véletlen /Java Singleton osztály
John Squirrels
Szint
San Francisco

Java Singleton osztály

Megjelent a csoportban
Szia! Ma a különböző tervezési minták részleteibe merülünk bele, kezdve a Java Singleton mintával. Tekintsük át: mit tudunk általában a tervezési mintákról? A tervezési minták olyan bevált gyakorlatok, amelyeket számos ismert probléma megoldására alkalmazhatunk. A tervezési minták általában nem kötődnek semmilyen programozási nyelvhez. Tekints rájuk úgy, mint egy olyan ajánláskészletre, amely segít elkerülni a hibákat és a kerék újrafeltalálását.Tervezési minták: Singleton - 1

Mi az a szingli a Java nyelven?

A Singleton az egyik legegyszerűbb osztályszintű tervezési minta. Néha az emberek azt mondják, hogy "ez az osztály egyszemélyes", ami azt jelenti, hogy az osztály megvalósítja az egytagú tervezési mintát. Néha olyan osztályt kell írni, ahol a példányosítást egyetlen objektumra korlátozzuk. Például egy osztály, amely a naplózásért vagy a csatlakozásért felelős adatbázis. A singleton tervezési minta leírja, hogyan érhetjük el ezt. A singleton olyan tervezési minta, amely két dolgot tesz:
  1. Garantálja, hogy az osztálynak csak egy példánya lesz.

  2. Egyetlen globális hozzáférési pontot biztosít az adott példányhoz.

Ezért van két olyan jellemző, amely a szingli minta szinte minden megvalósítására jellemző:
  1. Egy magán kivitelező. Ez korlátozza az osztály objektumok létrehozásának lehetőségét magán az osztályon kívül.

  2. Nyilvános statikus metódus, amely visszaadja az osztály példányát. Ezt a módszert getInstance-nak hívják . Ez az osztálypéldány globális elérési pontja.

Megvalósítási lehetőségek

A singleton tervezési mintát többféleképpen alkalmazzák. Mindegyik lehetőség jó és rossz a maga módján. Mint mindig, itt sem létezik tökéletes lehetőség, de törekednünk kell egy ilyenre. Először is döntsük el, hogy mi számít jónak és rossznak, és milyen mérőszámok befolyásolják a tervezési minta különböző megvalósításainak értékelését. Kezdjük a jóval. Íme olyan tényezők, amelyek szaftosabbá és vonzóbbá teszik a megvalósítást:
  • Lusta inicializálás: a példány nem jön létre, amíg nincs rá szükség.

  • Egyszerű és átlátható kód: ez a mérőszám természetesen szubjektív, de fontos.

  • Menetbiztonság: megfelelő működés többszálas környezetben.

  • Nagy teljesítmény többszálú környezetben: kevés vagy semmilyen szálblokkolás erőforrás megosztása során.

Most a hátrányok. Felsorolunk olyan tényezőket, amelyek rossz színben tüntetik fel a megvalósítást:
  • Nincs lusta inicializálás: amikor az osztály betöltődik az alkalmazás indulásakor, függetlenül attól, hogy szükség van-e rá (paradox módon az IT világban jobb lustának lenni)

  • Összetett és nehezen olvasható kód. Ez a mérőszám is szubjektív. Ha a szeme elkezd vérezni, feltételezzük, hogy a megvalósítás nem a legjobb.

  • A menetbiztonság hiánya. Más szóval "szálveszély". Helytelen működés többszálú környezetben.

  • Gyenge teljesítmény többszálú környezetben: a szálak mindig vagy gyakran blokkolják egymást, amikor megosztanak egy erőforrást.

Kód

Most készen állunk arra, hogy megvizsgáljuk a különböző megvalósítási lehetőségeket, és jelezzük az előnyöket és hátrányokat:

Egyszerű


public class Singleton {
    private static final Singleton INSTANCE = new Singleton();
    
    private Singleton() {
    }
    
    public static Singleton getInstance() {
        return INSTANCE;
    }
}
A legegyszerűbb megvalósítás. Előnyök:
  • Egyszerű és átlátható kód

  • Menetbiztonság

  • Nagy teljesítmény többszálú környezetben

Hátrányok:
  • Nincs lusta inicializálás.
Az előző hiányosság kijavítására a második számú megvalósítást kapjuk:

Lusta inicializálás


public class Singleton {
  private static final Singleton INSTANCE;

  private Singleton() {}

  public static Singleton getInstance() {
    if (INSTANCE == null) {
      INSTANCE = new Singleton();
    }
    return INSTANCE;
  }
}
Előnyök:
  • Lusta inicializálás.

Hátrányok:
  • Nem cérnabiztos

Érdekes ez a megvalósítás. Lustán inicializálhatjuk, de elvesztettük a szál biztonságát. Semmi gond – mindent szinkronizálunk a harmadik számú megvalósításban.

Szinkronizált hozzáférés


public class Singleton {
  private static final Singleton INSTANCE;

  private Singleton() {
  }

  public static synchronized Singleton getInstance() {
    if (INSTANCE == null) {
      INSTANCE = new Singleton();
    }
    return INSTANCE;
  }
}
Előnyök:
  • Lusta inicializálás.

  • Menetbiztonság

Hátrányok:
  • Gyenge többszálú teljesítmény

Kiváló! A harmadik számú megvalósításban visszaállítjuk a menetbiztonságot! Persze lassú... Most a getInstance metódus szinkronizálva van, így egyszerre csak egy szál tudja végrehajtani. A teljes metódus szinkronizálása helyett valójában csak azt a részét kell szinkronizálnunk, amely inicializálja az új példányt. De nem használhatunk egyszerűen szinkronizált blokkot az új példány létrehozásáért felelős rész becsomagolására. Ezzel nem biztosítható a szál biztonsága. Az egész egy kicsit bonyolultabb. A megfelelő szinkronizálás az alábbiakban látható:

Duplán ellenőrzött zár


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;
    }
}
Előnyök:
  • Lusta inicializálás.

  • Menetbiztonság

  • Nagy teljesítmény többszálú környezetben

Hátrányok:
  • A Java korábbi, 1.5 alatti verziói nem támogatják (a volatile kulcsszó használata az 1.5-ös verzió óta rögzített)

Vegye figyelembe, hogy a megvalósítási lehetőség megfelelő működéséhez két feltétel egyikének teljesülnie kell. Az INSTANCE változónak véglegesnek vagy változékonynak kell lennie . Az utolsó megvalósítás, amelyről ma beszélünk, az osztálytartó singleton .

Osztálytartó


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;
   }
}
Előnyök:
  • Lusta inicializálás.

  • Menetbiztonság.

  • Nagy teljesítmény többszálú környezetben.

Hátrányok:
  • A helyes működéshez garantálni kell, hogy a singleton objektum hibamentesen inicializálódik. Ellenkező esetben a getInstance metódus első hívása ExceptionInInitializerError hibát eredményez , és minden további hívás NoClassDefFoundError hibát eredményez .

Ez a megvalósítás szinte tökéletes. Lusta, cérnabiztos és gyors. De van egy árnyalata, amint azt a hátrányok listája kifejti. A singleton minta különféle megvalósításainak összehasonlítása:
Végrehajtás Lusta inicializálás Menetbiztonság Többszálú teljesítmény Mikor kell használni?
Egyszerű - + Gyors Soha. Vagy esetleg amikor a lusta inicializálás nem fontos. De soha nem lenne jobb.
Lusta inicializálás + - Nem alkalmazható Mindig, ha nincs szükség többszálra
Szinkronizált hozzáférés + + Lassú Soha. Vagy esetleg amikor a többszálú teljesítmény nem számít. De soha nem lenne jobb.
Duplán ellenőrzött zár + + Gyors Ritka esetekben, amikor kivételeket kell kezelnie a szingli létrehozásakor (amikor az osztálytartó szingli nem alkalmazható)
Osztálytartó + + Gyors Amikor többszálra van szükség, és garantált, hogy a singleton objektum problémamentesen jön létre.

A singleton minta előnyei és hátrányai

Általánosságban elmondható, hogy egy szingli pontosan azt teljesíti, amit elvárnak tőle:
  1. Garantálja, hogy az osztálynak csak egy példánya lesz.

  2. Egyetlen globális hozzáférési pontot biztosít az adott példányhoz.

Ennek a mintának azonban vannak hiányosságai:
  1. Az egyszemélyes osztály sérti az egyetlen felelősség elvét: a szingli osztály a közvetlen feladatai mellett az esetek számát is szabályozza.

  2. Egy közönséges osztály szinglitől való függése nem látható az osztály közbeszerzési szerződésében.

  3. A globális változók rosszak. Végső soron egy szingli egy hatalmas globális változóvá válik.

  4. Az egyszó jelenléte csökkenti az alkalmazás egészének tesztelhetőségét, és különösen a szinglitonust használó osztályok tesztelhetőségét.

És ez az! :) Felfedeztük veled a Java Singleton Class-t. Mostantól életed hátralévő részében, amikor programozó barátaiddal beszélgetsz, nem csak azt említheted, hogy mennyire jó a minta, hanem néhány szót arról is, hogy mitől rossz. Sok sikert ennek az új tudásnak az elsajátításához.

Kiegészítő olvasmány:

Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION