speicher vor der Synchronisierung aktualisieren?
-
13-12-2019 - |
Frage
es wird im Java-Speichermodell erwähnt, dass:Wenn ein Thread einen synchronisierten Block im Rahmen der Freigabe des zugehörigen Monitors verlässt, erfordert das JMM, dass der lokale Prozessorcache in den Hauptspeicher geleert wird.Ähnlich, im Rahmen der Erfassung des Monitors beim Eingeben eines synchronisierten Blocks werden lokale Caches ungültig, sodass nachfolgende Lesevorgänge direkt in den Hauptspeicher und nicht in den lokalen Cache gehen.
warum also muss ich in diesem Code die Instanz als flüchtig deklarieren, da beim Betreten des zweiten Threads der Synchronisierungsblock direkt in den Hauptspeicher gelangt??
public final class MySingleton {
private static MySingleton instance = null;
private MySingleton() { }
public static MySingleton getInstance() {
if (instance == null) {
synchronized (MySingleton.class) {
if (instance == null) {
instance = new MySingleton();
}
}
}
return instance;
}
}
Ich meine, wenn ein anderer Thread in den Synchronisationsblock eintritt und die zweite Überprüfung durchführt, soll er wie erwähnt aus dem Hauptspeicher aktualisiert werden.
Lösung
Die Rennbedingung ist dies:
Faden A sieht
instance == NULL
und führt diesen Code ausinstance = new MySingleton();
.Das schreiben aninstance
ist sichtbar, aber das schreibt hineinMySingleton
sind noch nicht.Faden B sieht
instance != NULL
und beginnt an der Instanz zu arbeiten.Thread B arbeitet jetzt an einem Objekt, dessen Konstruktion er nicht sehen kann.
Wodurch instance
volatile löst das Problem, da die JDK-Speicherspezifikation ab JDK5 garantiert, dass Schreibvorgänge in nichtflüchtige Objekte in Bezug auf Schreibvorgänge in ein flüchtiges Objekt nicht in der falschen Reihenfolge angezeigt werden.Also jeder Thread, der sieht instance != NULL
muss die Instanz selbst sehen.
Andere Tipps
Sie müssen nicht volatil deklarieren, da sonst keine Garantie besteht, dass zwei Anrufe an getinstance () dieselbe Instanz zurückgeben werden.
Es gibt keine Garantie, dass der Hauptspeicher zugegriffen wird, nur ein cachekonsistenter Wert.d. H. Alle Threads sehen den gleichen Wert.
BTW: Sie wissen natürlich, dass es weitaus komplexer ist als nötig.Alles, was Sie brauchen, ist
generasacodicetagpre.macht viel dasselbe.