Singleton-Muster in Multi-threaded-Umgebung
Während mein interview, interviewer begann seine Frage mit singleton-Muster. Ich schrieb unten. Dann fragte er Sollten wir nicht überprüfen, für die Nichtigkeit innerhalb getInstance
Methode?
Antwortete ich mit, Es ist NICHT notwendig, da Mitglied ist statischer Typ und initialisiert wird an der gleichen Zeit. Aber, scheint, wie er war nicht zufrieden mit meiner Antwort.Bin ich richtig oder nicht ?
class Single {
private final static Single sing = new Single();
private Single() {
}
public static Single getInstance() {
return sing;
}
}
Nun, nächste Frage, die er Fragen schreiben singleton-Klasse für die multi-Threading-Umgebung. Dann schrieb ich überprüfen singleton-Klasse.
class MultithreadedSingle {
private static MultithreadedSingle single;
private MultithreadedSingle() {
}
public static MultithreadedSingle getInstance() {
if(single==null){
synchronized(MultithreadedSingle.class){
if(single==null){
single= new MultithreadedSingle();
}
}
}
return single;
}
}
Dann, hatte er einen Einwand mit synchronized
an und überprüfen Sie und sagte ist Es nutzlos. Warum sind Sie die überprüfung zweimal, und warum sind Sie mit synchronisiert ? Ich habe versucht, ihn zu überzeugen, mit mehreren Szenario. Aber, hat er nicht.
Später zu Hause versuchte ich folgenden code, wo ich bin, mit einfachen singleton-Klasse mit mehreren Threads.
public class Test {
public static void main(String ar[]) {
Test1 t = new Test1();
Test1 t2 = new Test1();
Test1 t3 = new Test1();
Thread tt = new Thread(t);
Thread tt2 = new Thread(t2);
Thread tt3 = new Thread(t3);
Thread tt4 = new Thread(t);
Thread tt5 = new Thread(t);
tt.start();
tt2.start();
tt3.start();
tt4.start();
tt5.start();
}
}
final class Test1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " : " + Single.getInstance().hashCode());
}
}
}
class Single {
private final static Single sing = new Single();
private Single() {
}
public static Single getInstance() {
return sing;
}
}
Unten ist die Ausgabe :
Thread-0 : 1153093538
Thread-0 : 1153093538
Thread-0 : 1153093538
Thread-0 : 1153093538
Thread-0 : 1153093538
Thread-4 : 1153093538
Thread-1 : 1153093538
Thread-2 : 1153093538
Thread-3 : 1153093538
Thread-3 : 1153093538
Thread-3 : 1153093538
Thread-3 : 1153093538
Thread-3 : 1153093538
Thread-2 : 1153093538
Thread-2 : 1153093538
Thread-2 : 1153093538
Thread-2 : 1153093538
Thread-1 : 1153093538
Thread-1 : 1153093538
Thread-1 : 1153093538
Thread-1 : 1153093538
Thread-4 : 1153093538
Thread-4 : 1153093538
Thread-4 : 1153093538
Thread-4 : 1153093538
So, Frage ist, Ist es erforderlich, dass synchronize
oder/und Doppel-check-Methode, die in den multi-Threading-Umgebung ? Wie es scheint, meinen ersten code selbst (ohne jede zusätzliche Zeile code) war die Antwort für beide Fragen. Jede Korrektur und wissen zu teilen, werden geschätzt.
- Der einzige Einwand, den ich habe, um das erste Beispiel ist das kleingeschriebene "s" in der Klasse "Single" 😉 ich sehe keine race conditions. Entweder in der Klasse oder in jedem potenziellen Kunden, der vielleicht call " - Single.getInstance()",
- korrigiert alle 😉 Man kann Sie Bearbeiten, wenn ich das noch verpasst 🙂
- Keine "Korrekturen", die wirklich benötigt: aber die "oberen Fall" ist auf jeden Fall guter Stil. Zu deiner Frage: ich Stimme völlig mit yshavit und Evgeniy Dorofeev. Bitte fühlen Sie sich frei, um upvote beide. und "akzeptieren", wenn Sie auch einverstanden.
- völlig mit Ihnen einverstanden. Aber, ich würde warten, für ein paar mehr Stunden zu bekommen mehr Antworten 🙂 Da sein der die meisten faq im interview, also gerne mehr sehen Antwort 🙂
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ihre erste Beispiel ist absolut richtig, und ist in der Regel der am günstigsten gelegene "idiom" für singletons. Der andere ist ein single-element enum:
Sich die beiden Ansätze sehr ähnlich sind, es sei denn, die Klasse Serialisierbar ist, in welchem Fall die enum-Ansatz ist viel einfacher zu bekommen Recht-aber wenn die Klasse nicht Serializable, ich eigentlich lieber Ihren Ansatz der enum ein, als eine stilistische Sache. Watch out für die "zufälligerweise" immer Serialisierbar durch Implementierung einer Schnittstelle oder erweitern einer Klasse selbst Serialisierbar sind.
Sind Sie auch zu Recht über den zweiten Scheck für die Nichtigkeit in das double-checked-lock Beispiel. Jedoch, die
sing
Feld muss werdenvolatile
für diese Arbeit in Java; ansonsten gibt es keine formalen "passiert-vor" Kante zwischen einem thread schreiben zusing
und einem anderen thread zu Lesen. Dies kann dazu führen, dass der zweite thread zu sehennull
obwohl der erste thread der Variablen zugewiesen, oder, wenn diesing
Instanz hat Stand, könnte es sogar zu, dass der zweite thread zu sehen, nur einige, dass der Staat (Sie sehen ein teilweise konstruiertes Objekt).synchronized
war es nicht hilfreich ? Angenommen werden zwei thread-pass erste Nichtigkeit, sondern nur thread wird erlaubt, innerhalbsynchronized
und da sind wir wieder prüfen, ob Nichtigkeit vor der Initialisierung.Auch, warum sollten wirenum
oder eine andere Methode für die multi-Threading-Umgebung. Wenn wir erreichen können, durch einfachste Beispiel ? :svolatile
.1) - Klasse #1 ist gut für Multithread-Umgebung
2) Klasse #2 ist ein singleton mit lazy-Initialisierung und double-checked locking, das ist ein bekanntes Muster und es braucht, um die Synchronisierung zu verwenden. Aber deine Umsetzung ist gebrochen, es braucht
volatile
auf dem Feld. Finden Sie heraus, warum in diesem Artikel http://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking--clever--but-broken.html3) ein Singleton mit einer Methode nicht verwenden müssen, faul Muster, weil seine Klasse geladen und initialisiert nur bei der ersten Verwendung.
Ihre erste Antwort scheint zu sein, gut für mich, da gibt es keine chance auf eine race-Bedingung zu löschen.
Als für wissen zu teilen, ist der beste Ansatz zur Implementierung eines singleton in Java ist die Verwendung von Enum. Erstellen Sie ein enum mit genau einer Instanz, und das ist es. Für code-sample -
Vom guten Buch Effektive Java -
laut Doppel-checked_locking, es ist wahrscheinlich der beste Weg,
oder mit dem Initialization on demand holder idiom
In Fall #2 hinzufügen 'flüchtigen' Schlüsselwort, um das statische Feld 'single'.
Betrachten Sie dieses Szenario, wenn mit Double-Checked-Locking
Kommen wir nun zu der volatile-Schlüsselwort.
Volatile-Variablen sind immer schriftlich in den Arbeitsspeicher. Somit werden keine cache-Inkohärenz.