Влияет ли энергозависимое на энергонезависимые переменные? - PullRequest
10 голосов
/ 29 мая 2011

Хорошо, предположим, у меня есть набор переменных, одна из которых объявлена ​​как volatile:

int a;
int b;
int c;
volatile int v;

Если один поток выполняет запись во все четыре переменные (запись в v последняя), а другой поток выполняет чтение из всех четырех переменных (чтение из v первая), видит ли этот второй поток значения, записанные в a, b и c первым потоком, даже если они сами не объявлены энергозависимыми? Или он может видеть устаревшие значения?

Поскольку, похоже, существует некоторая путаница: я не пытаюсь делать что-то небезопасное. Я просто хочу понять модель памяти Java и семантику ключевого слова volatile. Чистое любопытство.

Ответы [ 4 ]

12 голосов
/ 29 мая 2011

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

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

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

Вы не упоминаете второе условие, имеющее значение true для вашего примера, но мы можем проверитьэто все равно.Модель для writer выглядит следующим образом:

  • Запись во все энергонезависимые переменные, при условии, что никакой другой поток не будет пытаться их прочитать.
  • По завершении запишите значение в переменную volatile guard, которое указывает на то, что критерии считывателей удовлетворены.

считыватели работают следующим образом:

  • Считайте переменную volatile guard в любое время, и если ее значение соответствует критериям, тогда
  • Считайте другие энергонезависимые переменные.

Читатели не должны читать другие не-volatile переменные, если переменная volatile guard еще не указывает правильное значение.

Переменная guard действует как гейт.Оно закрыто до тех пор, пока средство записи не установит для него определенное значение или набор значений, которые все соответствуют критериям указания того, что ворота теперь открыты.Энергонезависимые переменные охраняются за воротами.Читатель не имеет права читать их, пока не откроются ворота.Когда ворота открыты, читатель увидит непротиворечивое представление набора энергонезависимых переменных.

Обратите внимание, что не безопасно запускать этот протокол повторно.Автор не может продолжать изменять энергонезависимые переменные, как только он открыл ворота.В этот момент несколько потоков чтения могут считывать эти другие переменные, и они могут - хотя это не гарантировано - см. Обновления этих переменных.Просмотр некоторых, но не всех этих обновлений приведет к противоречивым представлениям набора.

Резервное копирование заключается в том, чтобы управлять доступом к набору переменных без

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

Копирование поверх переменной volatile guard - это умный трюк, который нельзя делать случайно.Последующие обновления программы могут нарушать вышеупомянутые хрупкие условия, устраняя гарантии согласованности, предоставляемые моделью памяти Java.Если вы решите использовать эту технику, четко запишите ее инварианты и требования в коде.

6 голосов
/ 29 мая 2011

Да. volatile, блокировки и т. Д. Устанавливают отношение произойдет до , но оно влияет на все переменные (в новой модели памяти Java (JMM) из Java SE 5 / JDK 1.4). Вид делает его полезным для непримитивных летучих веществ ...

1 голос
/ 29 мая 2011

видит ли этот второй поток значения, записанные в a, b и c первым потоком, даже если они сами не объявлены как volatile?Или он может видеть устаревшие значения?

Вы получите устаревшие чтения, b / c, вы не можете гарантировать, что значения a, b, c являются теми, которые установлены после чтения v. Использованиеконечный автомат (но вам нужен CAS для изменения состояния) - это способ решения подобных проблем, но он выходит за рамки обсуждения.

Возможно, эта часть неясна, после записи в v и чтения сначала из v вы получите правильные результаты (не устаревшие операции чтения), основная проблема заключается в том, что если вы выполните if (v==STATE1){...proceed...}, нет никакой гарантии, что какой-то другой поток не будет изменять состояние a / b / c.В этом случае будет состояние чтения.Если вы измените a / b / c + v только один раз, вы получите правильный результат.

Освоение параллелизма и свободных от блокировок структур - действительно сложная задача.У Дуга Ли есть хорошая книга, и большинство выступлений / статей доктора Клиффа Клика - замечательное богатство, если вам нужно что-то начать копать.

0 голосов
/ 30 мая 2011

Да, энергозависимая запись «происходит до» следующего энергозатратного чтения по той же переменной.

Хотя @seh прав насчет проблем согласованности с несколькими переменными, существуют варианты использования, требующие меньшей согласованности.

Например, поток записи обновляет некоторые переменные состояния;читатель поток отображает их быстро.Между переменными нет особой связи, нам нужно только быстро прочитать новые значения.Мы могли бы сделать каждую переменную состояния изменчивой.Или мы могли бы использовать только одну переменную volatile для защиты видимости.

Однако , экономия только на бумаге, с точки зрения производительности, разницы практически нет.В любой версии каждая переменная состояния должна быть «сброшена» писателем и «загружена» читателем.Нет бесплатного обеда.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...