Safe Publication (güvenli yayınlama) — bir nesnenin iş parçacıkları arasında güvenli bir şekilde dağıtılmasını garantileyen bir mekanizmadır: bir iş parçacığı bir nesne oluşturup başlatırsa, diğer iş parçacığı her zaman tamamen yapılandırılmış nesneyi görür, yarı yapılandırılmış durumunu değil.
Safe publication olmadan race condition'lar ortaya çıkabilir: bir iş parçacığı, konstrüktör çalıştıktan sonra bile, nesnenin henüz başlatılmamış bir kısmını görebilir.
Safe publication’ı sağlamanın yolları:
Örnek (unsafe):
public class Holder { private int n; public Holder(int n) { this.n = n; } } Holder holder; void publish() { holder = new Holder(42); } // Güvenlik garanti edilmez
Tamamen yapılandırılmamış nesneler görünür olabilir!
Örnek (safe):
volatile Holder holder; void publish() { holder = new Holder(42); } // holder'ı okumak da güvenli olacaktır
Eğer nesnede tüm alanlar final ise, bu her zaman safe publication'ı garanti eder mi?
Cevap: Hayır, sadece yeni nesneye olan referans konstrüktörün tamamlanmasından önce yayınlanırsa. Eğer referans, konstrüktör tamamlanmadan diğer iş parçacıklarına aktarılırsa, alanlar tam olarak başlatılmamış olabilir. Konstrüktör çalışırken 'this' veya tamamlanmamış nesnelere referans yayınlamaktan kaçınılmalıdır.
Örnek (tehlikeli!):
public class PublishEscape { public static PublishEscape instance; public PublishEscape() { instance = this; // Kötü! this konstrüktörün tamamlanmasından önce yayınlanıyor } }
Hikaye
Geliştirici, konstrüktör tamamlanmadan önce statik bir alanda Service örneğine referans veriyordu. Sonuç olarak, diğer bir iş parçacığı yarı yapılandırılmış bir nesne aldı ve bu üretimde öngörülemeyen davranışlara yol açtı.
Hikaye
Web uygulamasında singleton nesneleri ek bir senkronizasyon olmadan oluşturuldu. Yük altında bazı iş parçacıkları null veya yanlış bir şekilde başlatılmış alanlar aldı ve bu da Intermittent NullPointerException'a neden oldu.
Hikaye
Kütüphanede iş parçacıkları arasında cache için normal bir List kullanıldı — safe publication eksikti, başlatma yeni iş parçacıkları için görünürlük sağlamıyordu. Sonuç olarak, cache kaotik bir şekilde çalıştı ve veri bütünlüğünü ihlal etti.