Safe Publication (bezpieczna publikacja) to gwarantowane bezpieczne przekazywanie obiektu między wątkami: jeśli jeden wątek tworzy i inicjalizuje obiekt, inny wątek zawsze zobaczy w pełni skonstruowany obiekt, a nie jego częściowo zainicjalizowany stan.
Bez safe publication można napotkać race condition: jeden wątek widzi nie-zainicjalizowaną część obiektu, nawet jeśli konstruktor już zakończył działanie.
Sposoby zapewnienia safe publication:
Przykład (niebezpieczne):
public class Holder { private int n; public Holder(int n) { this.n = n; } } Holder holder; void publish() { holder = new Holder(42); } // Bezpieczeństwo nie jest gwarantowane
Mogą być widoczne nie w pełni skonstruowane obiekty!
Przykład (bezpieczne):
volatile Holder holder; void publish() { holder = new Holder(42); } // Odczyt holdera również będzie bezpieczny
Czy jeśli wszystkie pola w obiekcie są final, to czy zawsze gwarantuje to safe publication?
Odpowiedź: Nie, tylko jeśli odniesienie do nowego obiektu zostanie opublikowane przed zakończeniem konstruktora. Jeśli odniesienie trafia do innych wątków przed zakończeniem konstruktora, pola mogą być nie w pełni zainicjalizowane. Należy unikać publikowania this lub odniesień do nie w pełni skonstruowanych obiektów podczas wykonywania konstruktora.
Przykład (niebezpieczne!):
public class PublishEscape { public static PublishEscape instance; public PublishEscape() { instance = this; // Źle! this jest publikowane przed zakończeniem konstruktora } }
Historia
Programista przypisywał odniesienie do instancji Service w polu dostępnym przez static, przed zakończeniem konstruktora. W rezultacie inny wątek otrzymał częściowo skonstruowany obiekt, co spowodowało nieprzewidywalne zachowanie w produkcji.
Historia
W aplikacji webowej obiekty singleton były tworzone bez dodatkowej synchronizacji. Pod obciążeniem część wątków otrzymywała null lub niepoprawnie zainicjalizowane pola, co prowadziło do Intermittent NullPointerException.
Historia
W bibliotece używano zwykłego List do cache między wątkami - brakowało safe publication, inicjalizacja nie gwarantowała widoczności dla nowych wątków. W rezultacie cache działał chaotycznie, naruszając integralność danych.