Происходит ли волатильное чтение - до волатильной записи?

Я пытаюсь понять, почему этот пример является правильно синхронизированной программой:

a - volatile
Thread1:
x=a
Thread2:
a=5

Поскольку существуют конфликтующие обращения (есть запись и чтение a), поэтому в каждом последовательном выполнении последовательности должно происходить - до отношения между этими обращениями. Предположим, что одно из последовательных выполнений:

1. x=a
2. a=5

Происходит 1 - до 2, почему?

Ответ 1

Нет, волатильное чтение перед (в порядке синхронизации) волатильная запись одной и той же переменной не обязательно происходит - перед изменением записи.

Это означает, что они могут находиться в "гонке данных", потому что они "конфликтующие обращения, не упорядоченные с помощью отношения" произойдет раньше ". Если это действительно так, все программы содержат расы данных:) Но это, вероятно, ошибка спецификации. Неустойчивое чтение и запись никогда не следует рассматривать как гонку данных. Если все переменные в программе нестабильны, все исполнения тривиально последовательно последовательны. см. http://cs.oswego.edu/pipermail/concurrency-interest/2012-January/008927.html

Ответ 2

1 случается - до 2, почему?

Я не уверен на 100%, что понимаю ваш вопрос.

Если у вас есть изменчивая переменная a и один поток читает из нее, а другой пишет в нее, порядок этих обращений может быть в любом порядке. Это состояние гонки. То, что гарантируется JVM и моделью памяти Java (JMM), зависит от того, какая операция выполняется первой.

Запись могла произойти, и чтение увидит обновленное значение. Или запись может произойти после чтения. Таким образом, x может быть либо 5 либо предыдущим значением a.

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

Я не уверен, поэтому позвольте мне быть более конкретным. "Происходит перед отношением" с volatile означает, что все предыдущие операции записи в память в volatile переменной перед чтением той же переменной гарантированно завершатся. Но эта гарантия никоим образом не объясняет время между двумя volatile операциями, которое зависит от состояния гонки. Читатель гарантированно видел запись, но только если запись произошла до чтения.

Вы можете подумать, что это довольно слабая гарантия, но в потоках, производительность которых значительно улучшается благодаря использованию локального кэша ЦП, чтение значения поля может происходить из сегмента кэшированной памяти, а не из центральной памяти. Гарантия имеет решающее значение для гарантии того, что локальная память потоков становится недействительной и обновляется, когда происходит volatile чтение, чтобы потоки могли обмениваться данными соответствующим образом.

Опять же, JVM и JMM гарантируют, что если вы читаете из volatile поля a, то любые записи в то же поле, которые произошли до чтения, будут видны им - записанное значение будет правильно опубликовано и доступно для просмотра. читающая ветка. Однако эта гарантия никоим образом не определяет порядок. Это не говорит о том, что запись должна произойти до чтения.

Ответ 3

Извините, но вы не можете сказать правильно, как JVM будет оптимизировать код в зависимости от "модели памяти" JVM. Вы должны использовать инструменты высокого уровня Java для определения того, что вы хотите.

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

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

http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html

Ответ 4

Летучий и бывает-прежде полезен, когда считывание поля приводит к некоторому условию. Например:

volatile int a;
int b =0;
Thread-1:
   b = 5;
   a = 10;
Thread-2
   c = b + a;

В этом случае не происходит - раньше, a может быть либо 10, либо 0, а b может быть либо 5, либо 0, так что результатом c может быть либо 0, 5, 10, либо 15. Если чтение подразумевает какое-то другое условие, тогда, например, устанавливается событие-before:

int b = 0;
volatile int a = 0;
Thread-1:
   b = 5
   a = 10;
Thread 2: 
   if(a == 10){
      c = b + a;
   }

В этом случае вы обеспечите c = 15, потому что чтение a==10 означает, что запись b = 5 происходит до записи a = 10

Изменить: обновление порядка добавления, как указано, несогласованность Gray