Musí sa synchronizované kľúčové slovo aplikovať na každú metódu triedy, ktorá implementuje vzor ako jeden?
public class Singleton {
private Singleton(){}
public synchronized static Singleton getInstance()
{
if(instance == null)
instance = new Singleton ();
return instance;
}
public void DoA(){
}
}
Keďže Singletons nevystavujú verejnosťkonštruktér a metóda getInstance () je synchronizovaná, nie je potrebné synchronizovať metódu DoA a akékoľvek iné verejné metódy vystavené triedou Singleton.
Je toto odôvodnenie správne?
odpovede:
17 pre odpoveď č. 1Je to rovnako ako každá iná trieda, môže alebo nemusí byť potrebná ďalšia synchronizácia.
Zoberme si nasledujúci príklad:
public class Singleton {
private Singleton() {}
public synchronized static Singleton getInstance() { ... }
private int counter = 0;
public void addToCounter(int val) {
counter += val;
}
}
Ak má byť trieda použitá z viacerých vlákien, addToCounter()
má závodný stav. Jeden spôsob, ako to opraviť je tým, že addToCounter()
synchronizované:
public synchronized void addToCounter(int val) {
count += val;
}
Existujú aj iné spôsoby, ako opraviť stav pretekov, napríklad použitím AtomicInteger
:
private final AtomicInteger counter = new AtomicInteger(0);
public void addToCounter(int val) {
counter.addAndGet(val);
}
Tu sme podmienku preteku fixovali bez použitia synchronized
.
9 pre odpoveď č. 2
Účelom triedy Singleton je, že je najviac jedna inštancia a že všetky vlákna majú prístup k rovnakému objektu.
Ak by ste synchronizáciu nekombinovali getInstance
môže dôjsť k nasledovnému postupu
Závit1 vstupuje getInstance()
Závit2 vstupuje getInstance()
Thread1 vyhodnocuje instance == null
na true
Thread2 vyhodnocuje instance == null
na true
Thread1 priradí instance
a vráti sa
Thread2 reprideľuje instance = new Singleton()
a vráti sa.
Teraz majú vlákna rozdielnu inštanciu triedy Singleton, čo by sa tomuto vzoru malo zabrániť.
Synchronizácia zabraňuje tomu, aby obe vlákna mohli pristupovať k rovnakému bloku kódu súčasne. Takže synchronizácia je potrebná v prostredí s viacerými vláknami pri inštancii tried singleton.
Teraz predpokladáme, že sa pokúsi viacero vlákienprístup k metódam Singletons súčasne synchronizácia môže byť potrebné aj pri týchto metódach. Najmä ak menia dáta namiesto toho, aby len čítali, je to pravda.
1 pre odpoveď č. 3
Správny (najlepší skutočný) spôsob, ako používať Singleton
private static singleton getInstance() {
if (minstance == null) {
synchronized (singleton.class) {
if (minstance == null) {
minstance = new singleton();
}
}
}
return minstance;
}
1 pre odpoveď č. 4
lenivé inicializácie a bezpečné riešenie závitov:
public class Singleton {
public static class SingletonHolder {
public static final Singleton HOLDER_INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.HOLDER_INSTANCE;
}
}