Ich habe diese Art von Code sehr oft in Projekten gesehen, wo die Anwendung einen globalen Datenhalter haben möchte, also verwenden sie einen statischen Singleton, auf den jeder Thread zugreifen kann.Wie ist die Speichersichtbarkeit von Variablen, auf die in statischen Singletons in Java zugegriffen wird?
public class GlobalData {
// Data-related code. This could be anything; I've used a simple String.
//
private String someData;
public String getData() { return someData; }
public void setData(String data) { someData = data; }
// Singleton code
//
private static GlobalData INSTANCE;
private GlobalData() {}
public synchronized GlobalData getInstance() {
if (INSTANCE == null) INSTANCE = new GlobalData();
return INSTANCE;
}
}
Ich hoffe, es ist einfach zu sehen, was vor sich geht. Man kann jederzeit auf jedem Thread GlobalData.getInstance().getData()
anrufen. Wenn zwei Threads setData() mit unterschiedlichen Werten aufrufen, auch wenn Sie nicht garantieren können, welcher "gewinnt", mache ich mir darüber keine Sorgen.
Aber Thread-Sicherheit ist hier nicht mein Anliegen. Worüber ich besorgt bin, ist die Sichtbarkeit des Speichers. Wenn in Java eine Speicherbarriere vorhanden ist, wird der zwischengespeicherte Speicher zwischen den entsprechenden Threads synchronisiert. Eine Speicher Schranke passiert, wenn durch Synchronisierungen vorbei, flüchtige Variablen Zugriff usw.
das folgende Szenario in chronologischer Reihenfolge geschieht Stellen Sie sich vor:
// Thread 1
GlobalData d = GlobalData.getInstance();
d.setData("one");
// Thread 2
GlobalData d = GlobalData.getInstance();
d.setData("two");
// Thread 1
String value = d.getData();
Ist es nicht möglich, dass der letzte Wert von value
in Thread 1 Dose immer noch "one"
? Der Grund dafür ist, dass Thread 2 niemals nach dem Aufruf von d.setData("two")
irgendwelche synchronisierten Methoden aufgerufen hat, so dass es nie eine Speicherbarriere gab? Beachten Sie, dass die Speicherbarriere in diesem Fall jedes Mal auftritt, wenn getInstance()
aufgerufen wird, weil es synchronisiert ist.
Sie sagen 'Man kann GlobalData.getInstance(). GetData() jederzeit auf jedem Thread aufrufen. Es ist threadsicher, also mache ich mir darüber keine Sorgen, aber es ist eigentlich nicht threadsicher, genau wegen des Szenarios, das du beschreibst. Bei der Threadsicherheit geht es nicht nur darum, ein Objekt in einem inkonsistenten Zustand zu sehen. Es geht auch darum, veraltete Daten zu sehen. – yair
@yair Ja, aber ich habe wirklich versucht, den Aspekt der Speicher-Sichtbarkeit zu untersuchen, im Gegensatz zu inkonsistenten Zuständen, die auf der synchronen Ausführung basieren. –