Safe Publication (безопасная публикация) — это гарантированное безопасное распространение объекта между потоками: если один поток создает и инициализирует объект, другой поток всегда увидит полностью сконструированный объект, а не его частично инициализированное состояние.
Без safe publication можно получить race condition: один поток видит не-инициализированную часть объекта, даже если конструктор уже отработал.
Способы обеспечения safe publication:
Пример (unsafe):
public class Holder { private int n; public Holder(int n) { this.n = n; } } Holder holder; void publish() { holder = new Holder(42); } // Безопасность не гарантирована
Могут быть видны не полностью сконструированные объекты!
Пример (safe):
volatile Holder holder; void publish() { holder = new Holder(42); } // Чтение holder тоже будет safe
Если в объекте все поля final, гарантирует ли это safe publication всегда?
Ответ: Нет, только если ссылка на новый объект будет опубликована до конца конструктора. Если ссылка уходит в другие потоки до завершения конструктора — поля могут быть не инициализированы полностью. Следует избегать публикации this или ссылок на не до конца сконструированные объекты во время исполнения конструктора.
Пример (опасно!):
public class PublishEscape { public static PublishEscape instance; public PublishEscape() { instance = this; // Плохо! this публикуется до конца конструктора } }
История
Разработчик присваивал ссылку на Service экземпляр в поле, доступном через static, до завершения конструктора. В результате другой поток получил partially-constructed объект, что вызвало непредсказуемое поведение в продакшене.
История
В веб-приложении singleton-объекты создавались без дополнительной синхронизации. Под нагрузкой часть потоков получала null или некорректно инициализированные поля, что приводило к Intermittent NullPointerException.
История
В библиотеке использовали обычный List для кеша между потоками — отсутствовала safe publication, инициализация не гарантировала видимость новым потокам. В итоге кеш работал хаотично, нарушая целостность данных.