Безопасная публикация без происшествий? Во всяком случае, кроме финала?
Согласно JCP (16.2.2. Безопасная публикация):
Это происходит до того, как гарантия на самом деле является более сильным обещанием наглядности и упорядоченности, чем безопасное издание. Когда X безопасно публикуется от A до B, безопасная публикация гарантирует видимость состояния X, но не состояния других переменных, которые могли коснуться. Но если A помещает X в очередь - до того, как B извлекает X из этой очереди, B не только видит X в состоянии, в котором A его покинул (при условии, что X не был впоследствии изменен A или кем-либо еще), но B видит все, что А делал перед передачей (опять же, с учетом того же предостережения)
Я задаюсь вопросом, когда безопасная публикация может быть без предшествующего события, то есть без использования volatile / atomics или синхронизации (или через структуры, такие как AQS, которые используют любой из перечисленных внутри)?
Один случай - заключительные поля в неизменяемом объекте, где вы можете опубликовать его без каких-либо дополнительных шагов.
Есть ли другие случаи?
UPD: перечитайте 3.5.3. Безопасная публикация идиом, другой случай - "Инициализация ссылки на объект из статического инициализатора". Кажется, теперь это все варианты.
3 ответа
Я ничего не знаю, кроме final
и взгляд на http://java.sun.com/docs/books/jls/third_edition/html/memory.html кажется, подтверждает это. Глава 17.4 посвящена всему, кроме final
, что объясняется отдельно в 17.5.
Следует отметить, однако, что все, что находится внутри JVM, всегда должно быть видно, прежде чем это может способствовать гонке данных в коде Java. Это затрагивает в основном длины массивов, указатели виртуальных таблиц и содержимое строк. Они никогда не могут рассматриваться как неинициализированные или иным образом противоречивые.
Весь список случаев, которые вы можете найти в Java In Concurrency:
Чтобы безопасно опубликовать объект, и ссылка на объект, и состояние объекта должны быть видны другим потокам одновременно. Правильно сконструированный объект может быть безопасно опубликован:
Инициализация ссылки на объект из статического инициализатора;
Сохранение ссылки на него в энергозависимом поле или AtomicReference;
Сохранение ссылки на него в конечном поле правильно построенного объекта; или же
Сохранение ссылки на него в поле, которое должным образом охраняется блокировкой.
Статическая инициализация выполняется внутри synchronized(class)
так что это очень сильно.
в то время как final
семантика слабее, я сомневаюсь, что реализация действительно так слаба.
У Дуга Ли было предложение по более примитивным заборам, http://cs.oswego.edu/pipermail/concurrency-interest/2009-January/005743.html