Publication Sécurisée (safe publication) — c'est une garantie de diffusion sécurisée d'un objet entre les threads : si un thread crée et initialise un objet, un autre thread verra toujours un objet entièrement construit et non son état partiellement initialisé.
Sans safe publication, on peut avoir une condition de concurrence : un thread voit une partie non initialisée de l'objet, même si le constructeur a déjà été exécuté.
Moyens d'assurer la publication sécurisée :
Exemple (non sécurisé) :
public class Holder { private int n; public Holder(int n) { this.n = n; } } Holder holder; void publish() { holder = new Holder(42); } // Sécurité non garantie
Peuvent être visibles des objets non entièrement construits !
Exemple (sécurisé) :
volatile Holder holder; void publish() { holder = new Holder(42); } // La lecture de holder sera également sécurisée
Si tous les champs de l'objet sont final, cela garantit-il toujours la publication sécurisée ?
Réponse : Non, seulement si la référence au nouvel objet est publiée avant la fin du constructeur. Si la référence est partagée avec d'autres threads avant la fin du constructeur, les champs peuvent ne pas être complètement initialisés. Il faut éviter de publier this ou des références à des objets pas encore complètement construits pendant l'exécution du constructeur.
Exemple (dangereux !) :
public class PublishEscape { public static PublishEscape instance; public PublishEscape() { instance = this; // Mauvais ! this est publié avant la fin du constructeur } }
Histoire
Le développeur a assigné une référence à une instance de Service dans un champ accessible via static, avant la fin du constructeur. En conséquence, un autre thread a reçu un objet partiellement construit, provoquant un comportement imprévisible en production.
Histoire
Dans une application web, des objets singleton étaient créés sans synchronisation supplémentaire. Sous charge, certains threads obtenaient null ou des champs mal initialisés, entraînant des NullPointerExceptions intermittentes.
Histoire
Dans la bibliothèque, un List classique était utilisé pour le cache entre les threads — la publication sécurisée faisait défaut, et l'initialisation ne garantissait pas la visibilité pour les nouveaux threads. En fin de compte, le cache fonctionnait de manière chaotique, compromettant l'intégrité des données.