2

Читая Java Параллелизм на практикеНеустойчивая гарантия безопасной публикации изменчивого объекта?

Я вижу:

Чтобы опубликовать объект безопасно, как ссылку на объект и состояние объекта должны быть сделаны видимыми для других потоков одновременно. Правильно построенный объект может быть безопасно опубликован:

  • Инициализация ссылки на объект от статического инициализатора
  • хранящим ссылки на него в летучее поле или AtomicReference
  • Сохранение ссылки на него в конечное поле правильно спроектированного объекта
  • Хранение ссылки на него в поле, которое должным образом защищено замком .

Однако я смущен о второй идиоме. Так как volatile может только гарантировать, что ссылка видна другой темой, но у нее нет синхронизации конструкции объекта, которую она ссылается на. Итак, как он может гарантировать правильное построение изменчивого объекта, то, что поток, который создает этот объект, прерывается другим потоком?

ответ

1

Reads and writes are atomic for all variables declared volatile (including long and double variables).

Последствие: volatile гарантирует, среди прочего, что переменная всегда считывается из памяти, совместно используемой всеми потоками - если значение публикуется в volatile переменной, она должна быть полностью построен раньше.
Другими словами, если значение volatile не публикуется, то никакие другие потоки не будут знать об этом - скорее всего, результат «незавершенного строительства» может находиться в кэше процессора или в памяти, которую JVM использует как «пространство I», m для использования в моих собственных целях, теневой код Java, не спрашивайте, что в нем, это не ваш бизнес ».

+0

Что, если переменная является ссылкой на массив? например, volatile int [] arr = new int [5]. Я знаю, что arr будет опубликован безопасно, как насчет после публикации, я делаю arr [0] = 100. Является ли этот поток безопасным? Я хочу сказать, что это гарантирует безопасную публикацию arr [0] = 100? –

+0

@GuifanLi Способ, которым я знаю/понимаю, нет гарантии на содержимое созданного экземпляра (или массива) после публикации. Возможно, я ошибаюсь (и немного занят на данный момент, чтобы найти ответ). –

4

Нам нужно показать, что построение объекта и присвоение его переменной volatile происходит до того, как она будет считана из этой переменной.

From JLS Chapter 17:

Если х и у являются действия той же нити и х предшествует у в программном порядке, то ро (х, у).

Таким образом, строительство объекта происходит перед он назначается летучей переменным, с точки зрения этого потока.

Если действие х синхронизирует-с следующим действием у, мы также имеем Hb (х, у).

А:

Если ро (х, у) и ро (у, г), то ро (х, г).

Если бы мы могли показать, что писать летучие переменное (действие у) синхронизирует-с чтения переменного (действие г), мы могли бы использовать транзитивность происходит, перед тем показать что строительство объекта (действие x) бывает-до чтение объекта. К счастью:

Запись в летучем переменной против (§8.3.1.4) синхронизирует-с все последующее чтение об любым потоком (где «последующее» определяется в соответствии с порядком синхронизации).

Таким образом, мы можем видеть, что правильно опубликованный таким образом объект является видимым для любого потока.

+0

Спасибо за ваш ответ, и он однозначно отвечает на мой вопрос. Кстати, из того, что я понимаю, «окончательное» ключевое слово может также гарантировать это, но почему это так? Я предполагаю, что механизм за этим отличается? –

1

volatile может гарантировать, что ссылка видна другой теме, но у нее нет синхронизации конструкции объекта, на которую она ссылается.

Да. Ты прав. Вы можете найти более подробную информацию о внутренних о летучих переменных вопрос ниже:

Difference between volatile and synchronized in Java

Так как это может гарантировать, что изменяемый объект правильно построен, что поток, который строит этот объект прерывается другой поток?

Вы должны использовать другие программные конструкции для безопасности потока: Использование synchronized конструкции или альтернатив synchronized конструкций.

См ниже связанного SE вопрос:

Avoid synchronized(this) in Java?

Смежные вопросы