Ho visto questo tipo di codice molto in progetti, in cui l'applicazione vuole un supporto globale dei dati, in modo da utilizzare un Singleton statica che qualsiasi thread può accedere.Qual è la visibilità della memoria delle variabili accessibili in singleton statici in Java?
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;
}
}
Spero sia facile vedere cosa sta succedendo. Si può chiamare GlobalData.getInstance().getData()
in qualsiasi momento su qualsiasi thread. Se due thread chiamano setData() con valori diversi, anche se non puoi garantire quale "vince", non sono preoccupato.
Ma thread-sicurezza non è la mia preoccupazione qui. Quello che mi preoccupa è la visibilità della memoria. Ogni volta che c'è una barriera di memoria in Java, la memoria cache viene sincronizzata tra i thread corrispondenti. Una barriera di memoria avviene quando passa attraverso sincronizzazioni, l'accesso a variabili volatili, ecc
Immaginate il seguente scenario accadendo in ordine cronologico:
// Thread 1
GlobalData d = GlobalData.getInstance();
d.setData("one");
// Thread 2
GlobalData d = GlobalData.getInstance();
d.setData("two");
// Thread 1
String value = d.getData();
Non è possibile che l'ultimo valore di value
in filo 1 può essere ancora "one"
? Il motivo è, filo 2 non ha mai chiamato i metodi sincronizzati dopo aver chiamato d.setData("two")
quindi non c'era mai una barriera di memoria? Si noti che la barriera di memoria in questo caso si verifica ogni volta che viene chiamato getInstance()
perché è sincronizzato.
Si dice 'Si può chiamare GlobalData.getInstance(). GetData() in qualsiasi momento su qualsiasi thread. È sicuro per i thread, quindi non sono preoccupato per questo, ma in realtà non è thread-safe esattamente a causa dello scenario che descrivi. La sicurezza del thread non riguarda solo il vedere un oggetto in uno stato incoerente. Riguarda anche la visualizzazione di dati obsoleti. – yair
@yair Sì, ma stavo davvero cercando di esaminare l'aspetto di visibilità della memoria rispetto agli stati incoerenti basati sull'esecuzione sincrona. –