Неустойчивые переменные и происходит перед заказом

У меня есть два потока:

Тема: 1

a = 1;
x = b;

Тема: 2

b = 1
y = a

Здесь a и b объявлены изменчивыми. Я не понял, как создается "случается-до" ребро между a = 1; и y = a; и между x = b; и b = 1;

Я понимаю, что с помощью переменной volatile можно предотвратить чтение устаревших значений из кэша потоков. Но как можно избежать изменчивой переменной - перед заказом.

В частности, я не понял этого:

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

Hoe это работает?

Ответ 1

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

Важное слово здесь - "последующее".

Здесь соответствующий бит спецификации языка Java 17.4.4 Порядок синхронизации:

Каждое исполнение имеет порядок синхронизации. Порядок синхронизации - это полный порядок по всем действиям синхронизации выполнения. Для каждого потока t порядок синхронизации действий синхронизации (§17.4.2) в t соответствует порядку программы (§ 17.4.3) t. Действия синхронизации индуцируют синхронизированную связь с действиями, определенную следующим образом:

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

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

Ответ 2

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

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

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

См. раздел JLS 17.4.4 Порядок синхронизации, который определяет слово "последующее" в этом контексте.

Ответ 3

Для анализа сначала укажите все возможные заказы синхронизации. они должны соответствовать порядку программирования. В вашем примере есть 6 возможных заказов.

 1       2       3       4       5       6
w(a)    w(a)    w(b)    w(a)    w(b)    w(b) 
r(b)    w(b)    w(a)    w(b)    w(a)    r(a)
w(b)    r(b)    r(b)    r(a)    r(a)    w(a)
r(a)    r(a)    r(a)    r(b)    r(b)    r(b)

Каждый порядок устанавливает некоторые действия перед отношениями. В (1) имеем w (a) - до r (a). В (6) имеем w (b) - до r (b). В (2) - (5) имеем оба.

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

Если это звучит слишком сложно, это так. В реальной жизни мы обычно ограничиваемся более простыми ситуациями, когда только один объект заблокирован/выпущен, или только одна изменчивая переменная читается и записывается. Тогда это не слишком сложно.