Jednokrevetni u Javi

1. Uvod

U ovom ćemo kratkom članku razgovarati o dva najpopularnija načina implementacije Singletona u običnu Javu.

2. Jednokrevetni na temelju klase

Najpopularniji pristup je implementacija Singletona stvaranjem redovite klase i osiguravanjem da ima:

  • Privatni konstruktor
  • Statično polje koje sadrži svoj jedini primjerak
  • Statička tvornička metoda za dobivanje instance

Također ćemo dodati informacijsko svojstvo, samo za kasniju upotrebu. Dakle, naša implementacija izgledat će ovako:

javna završna klasa ClassSingleton {private static ClassSingleton INSTANCE; private String info = "Početna klasa informacija"; private ClassSingleton () {} public static ClassSingleton getInstance () {if (INSTANCE == null) {INSTANCE = new ClassSingleton (); } povratak INSTANCE; } // geteri i postavljači}

Iako je ovo uobičajen pristup, važno je napomenuti da ga može biti problematično u scenarijima s više niti, što je glavni razlog korištenja Singletona.

Jednostavno rečeno, to može rezultirati u više slučajeva, što krši osnovno načelo uzorka. Iako postoje rješenja za zaključavanje ovog problema, naš sljedeći pristup rješava te probleme na korijenskoj razini.

3. Enum Singleton

Krećući se naprijed, nemojmo raspravljati o još jednom zanimljivom pristupu - a to je korištenje nabrajanja:

javni popis EnumSingleton {INSTANCE ("Informacije o početnoj klasi"); informacije o privatnom nizu; private EnumSingleton (String info) {this.info = info; } javni EnumSingleton getInstance () {return INSTANCE; } // geteri i postavljači}

Ovaj pristup ima serializaciju i sigurnost niti, zajamčenu samom implementacijom nabrajanja, koja interno osigurava da je dostupan samo jedan primjerak, ispravljajući probleme na koje je ukazano u provedbi na temelju klase.

4. Upotreba

Da se koristimo našim ClassSingleton, jednostavno moramo statički dobiti instancu:

ClassSingleton classSingleton1 = ClassSingleton.getInstance (); System.out.println (classSingleton1.getInfo ()); // Inicijalne informacije o klasi ClassSingleton classSingleton2 = ClassSingleton.getInstance (); classSingleton2.setInfo ("Informacije o novom razredu"); System.out.println (classSingleton1.getInfo ()); // Nova informacija o klasi System.out.println (classSingleton2.getInfo ()); // Nove informacije o nastavi

Što se tiče EnumSingleton, možemo ga koristiti kao bilo koji drugi Java Enum:

EnumSingleton enumSingleton1 = EnumSingleton.INSTANCE.getInstance (); System.out.println (enumSingleton1.getInfo ()); // Inicijalni podaci o nabrajanju EnumSingleton enumSingleton2 = EnumSingleton.INSTANCE.getInstance (); enumSingleton2.setInfo ("Novi podaci o nabrajanju"); System.out.println (enumSingleton1.getInfo ()); // Novi podaci o nabrajanju System.out.println (enumSingleton2.getInfo ()); // Novi podaci o nabrajanju

5. Uobičajene zamke

Singleton je varljivo jednostavan obrazac dizajna i malo je uobičajenih pogrešaka koje bi programer mogao počiniti prilikom stvaranja singletona.

Razlikujemo dvije vrste problema s jednostrukim krugovima:

  • egzistencijalni (treba li nam singleton?)
  • implementacijski (primjenjujemo li ga pravilno?)

5.1. Egzistencijalna pitanja

Konceptualno, singleton je vrsta globalne varijable. Općenito, znamo da globalne varijable treba izbjegavati - pogotovo ako su njihova stanja promjenjiva.

Ne kažemo da nikada ne bismo smjeli koristiti singletone. Međutim, kažemo da bi mogli postojati učinkovitiji načini organizacije našeg koda.

Ako implementacija metode ovisi o pojedinačnom objektu, zašto je ne proslijediti kao parametar? U ovom slučaju izričito pokazujemo o čemu metoda ovisi. Kao posljedicu, možemo lako ismijati ove ovisnosti (ako je potrebno) tijekom izvođenja testiranja.

Na primjer, pojedinačni tonovi često se koriste za obuhvatanje podataka o konfiguraciji aplikacije (tj. Veze s spremištem). Ako se koriste kao globalni objekti, postaje teško odabrati konfiguraciju za testno okruženje.

Stoga se, kada pokrenemo testove, proizvodna baza podataka pokvari podacima o testovima, što je teško prihvatljivo.

Ako nam treba singleton, mogli bismo razmotriti mogućnost delegiranja njegove instancije drugoj klasi - vrsti tvornice - koja bi se trebala pobrinuti za postojanje samo jednog primjerka singletona.

5.2. Provedbena pitanja

Iako se singletoni čine prilično jednostavnima, njihove implementacije mogu patiti od različitih problema. Sve rezultiraju činjenicom da bismo na kraju mogli imati više od samo jednog primjerka klase.

Sinkronizacija

Implementacija s privatnim konstruktorom koju smo gore predstavili nije sigurna u nitima: dobro funkcionira u jednonitnom okruženju, ali u višenitnom trebali bismo koristiti tehniku ​​sinkronizacije kako bismo zajamčili atomskost operacije:

javni sinkronizirani statički ClassSingleton getInstance () {if (INSTANCE == null) {INSTANCE = new ClassSingleton (); } povratak INSTANCE; }

Obratite pažnju na ključnu riječ sinkronizirano u deklaraciji metode. Tijelo metode ima nekoliko operacija (usporedba, instancija i povratak).

U nedostatku sinkronizacije, postoji mogućnost da dvije niti isprepleću svoja izvršavanja na takav način da izraz INSTANCIJA == null ocjenjuje do pravi za obje niti i, kao rezultat, dva primjerka ClassSingleton stvoriti se.

Sinkronizacija može značajno utjecati na performanse. Ako se ovaj kod često poziva, trebali bismo ga ubrzati pomoću različitih tehnika poput lijena inicijalizacija ili dvostruko provjereno zaključavanje (imajte na umu da ovo možda neće raditi kako se očekivalo zbog optimizacija kompajlera). Više pojedinosti možemo vidjeti u našem vodiču „Dvostruko provjereno zaključavanje jednim jednostrukim krugom“.

Više instanci

Postoji još nekoliko problema sa singletonima povezanim sa samim JVM-om zbog kojih bismo mogli završiti s više primjeraka singletona. Ova su pitanja prilično suptilna i dat ćemo kratki opis svakog od njih:

  1. Singleton bi trebao biti jedinstven po JVM-u. To bi mogao predstavljati problem distribuiranim sustavima ili sustavima čiji se interni dijelovi temelje na distribuiranim tehnologijama.
  2. Svaki učitavač klase može učitati svoju verziju singletona.
  3. Jedan pojedinac može se sakupljati smeće kad ga nitko nema. Ovaj problem ne dovodi do prisutnosti više pojedinačnih instanci odjednom, ali kad se ponovno stvori, instanca se može razlikovati od svoje prethodne verzije.

6. Zaključak

U ovom smo se brzom vodiču usredotočili na to kako implementirati Singleton obrazac koristeći samo jezgru Jave, te kako osigurati njegovu dosljednost i kako iskoristiti ove implementacije.

Potpuna implementacija ovih primjera može se naći na GitHubu.