La Safe Publication (pubblicazione sicura) è la garanzia di una diffusione sicura di un oggetto tra i thread: se un thread crea e inizializza un oggetto, un altro thread vedrà sempre l'oggetto completamente costruito, e non il suo stato parzialmente inizializzato.
Senza una safe publication, si possono verificare condizioni di competizione (race condition): un thread vede una parte non inizializzata dell'oggetto, anche se il costruttore ha già terminato.
Modi per garantire la safe publication:
Esempio (non sicuro):
public class Holder { private int n; public Holder(int n) { this.n = n; } } Holder holder; void publish() { holder = new Holder(42); } // Sicurezza non garantita
Possono essere visibili oggetti non completamente costruiti!
Esempio (sicuro):
volatile Holder holder; void publish() { holder = new Holder(42); } // La lettura di holder sarà anch'essa sicura
Se tutti i campi nell'oggetto sono finali, garantisce sempre una safe publication?
Risposta: No, solo se il riferimento al nuovo oggetto viene pubblicato prima della fine del costruttore. Se il riferimento viene accesso da altri thread prima del completamento del costruttore, i campi potrebbero non essere completamente inizializzati. Si dovrebbe evitare di pubblicare this o riferimenti ad oggetti non completamente costruiti durante l'esecuzione del costruttore.
Esempio (pericoloso!):
public class PublishEscape { public static PublishEscape instance; public PublishEscape() { instance = this; // Male! this viene pubblicato prima della fine del costruttore } }
Storia
Uno sviluppatore ha assegnato un riferimento a un'istanza del Service in un campo accessibile tramite static, prima del completamento del costruttore. Di conseguenza, un altro thread ha ottenuto un oggetto parzialmente costruito, causando comportamenti imprevedibili in produzione.
Storia
In un'app web, gli oggetti singleton venivano creati senza sincronizzazione aggiuntiva. Sotto carico, alcuni thread ottenevano null o campi inizializzati in modo errato, causando Intermittent NullPointerException.
Storia
Nella libreria si utilizzava una normale List come cache tra i thread — mancava la safe publication, l'inizializzazione non garantiva la visibilità ai nuovi thread. Alla fine, la cache funzionava in modo caotico, compromettendo l'integrità dei dati.