Изменение порядка в связи JMM "происходит до"

В JLS написано, что происходит до отношения JMM (раздел 17.4.5):

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

Меня интересуют примеры этого утверждения.

Правильно ли я понимаю, что примером этого может быть следующее:

Thread 1

x = 1
lock M
y = 2                            
unlock M ----------------------->Thread 2:

                                 lock M
                                 z = 3
                                 w = 4
                                 unlock M

Очевидно, что в этой трассировке выполнения существует связь между (x = 1) и (w = 4) «происходит раньше»:

(x = 1) happens-before (w = 4)

Также в этом случае (x = 1) заказывается с (w = 4) в трассе выполнения.

Thread 1 не использует переменную w. Следовательно, мы можем разместить его перед (x = 1), не нарушая логики Thread 1 и Thread 2.

Означает ли это, что если мы переупорядочиваем (x = 1) и (w = 4), то это происходит до того, как отношения между этими утверждениями сохранятся?

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


person Vitaly    schedule 13.01.2016    source источник
comment
Да, вот и все - отношение hb определяет, какие операции записи должны быть видны для операций чтения одной и той же переменной в потоках - если переменная правильно видна при чтении, соблюдены гарантии hb. Если поток 3 читает w, затем x, для него было бы законно, например, читать 4 и 0.   -  person assylias    schedule 14.01.2016


Ответы (2)


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

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

Таким образом, каждый оператор в методе Java выполняется перед каждым последующим оператором, но, конечно, JIT-компилятор и ЦП могут свободно переупорядочивать независимые операторы (и на самом деле они делают это довольно часто для оптимизации производительности). Иногда вы можете наблюдать это переупорядочение из другого потока, который не имеет отношений «происходит до» с текущим потоком.

person Tagir Valeev    schedule 14.01.2016
comment
Что, если существует транзитивная зависимость ... W зависит от Q, Q зависит от P, P зависит от X. Вы не можете гарантировать, что установка переупорядочения W и X не вызовет несоответствий, верно ?. Как JVM отслеживает такие переходные зависимости? - person TheLostMind; 14.01.2016
comment
@TheLostMind, конечно, отслеживает. Если в некоторых случаях отслеживание является слишком сложным или JVM не уверен на 100%, он просто откажется от переупорядочения (поскольку вы всегда можете выполнить код без переупорядочения, возможно, с худшей производительностью). Правильность абсолютно важна, и ею нельзя жертвовать ради производительности. - person Tagir Valeev; 14.01.2016

Поток 1 не использует переменную w

Вы не можете предположить, что это причина, поскольку на самом деле модель памяти Java не принимает во внимание, безопасно ли переупорядочивать инструкции в изолированном контексте потока, в отношении восприятия других вовлеченных потоков.
Без блокировки или барьера памяти JMM гарантирует только выполнение операторов в одном потоке.

В вашем случае у вас есть механизм блокировки для одного и того же объекта (M), поэтому происходит «происходит до».
synchronized (блокировка) или другие атомарные переменные в Java обрабатывают барьер памяти и атомарность . Для информации, volatile переменные и final присвоение переменных в конструкторе обрабатывают только барьер памяти.

Возьмем, к примеру, этот пример, имеющий дело с вообще нет барьера памяти:

Class Reordering {
  int x = 0, y = 0;
  public void writer() {
    x = 1;
    y = 2;
  }

  public void reader() {
    int r1 = y;
    int r2 = x;
  }
} 

Предположим, что этот код выполняется в двух потоках одновременно, и при чтении y отображается значение 2. Поскольку эта запись была произведена после записи в x, программист может предположить, что при чтении x должно отображаться значение 1. Однако записи могли быть переупорядочены. Если это произойдет, то может произойти запись в y, за ним может последовать чтение обеих переменных, а затем может произойти запись в x. В результате r1 имеет значение 2, а r2 имеет значение 0.

person Mik378    schedule 14.01.2016
comment
да. Но в вашем примере нет отношения hb. Вместо этого происходит гонка данных между двумя потоками. - person Vitaly; 16.01.2016