Разрешается ли переупорядочивание этой инструкции JLS или нет?

Согласно Спецификации языка Java (Пример 17.4 -1) следующий фрагмент (начиная с A == B == 0)...

Thread 1             Thread 2
--------             --------
r2 = A;              r1 = B;
B = 1;               A = 2;

... может привести к r2 == 2 и r1 == 1. Это связано с тем, что результат выполнения B = 1; не зависит от того, было ли выполнено r2 = A, поэтому JVM может свободно менять порядок выполнения этих двух инструкций. Другими словами, спецификация допускает следующее чередование:

Thread 1             Thread 2
--------             --------
B = 1;
                     r1 = B;
                     A = 2;
r2 = A;

что явно приводит к r2 == 1 и r1 == 1.

Мой вопрос:

Предположим, мы немного подправим пример:

Thread 1             Thread 2
--------             --------
r2 = A;              r1 = B;
monitorenter obj     monitorenter obj
monitorexit obj      monitorexit obj
B = 1;               A = 2;

где obj — ссылка, совместно используемая потоками.

Разрешено ли изменение порядка r2 = A и B = 1?


JLS говорит...

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

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

Разблокировка монитора происходит перед каждой последующей блокировкой этого монитора.

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


person aioobe    schedule 03.01.2013    source источник
comment
Разве это не будет зависеть от отслеживаемого кода? Если я правильно вас понял, эти строки мониторинга в любом случае можно было бы оптимизировать, поскольку нулевой код не имеет никакого эффекта и не перекрывается, по крайней мере, в теории.   -  person Sam    schedule 04.01.2013
comment
Ну, если они не влияют на семантику, то да, наверное, их можно удалить. Но если они предотвращают изменение порядка инструкций, они действительно влияют на семантику, верно?   -  person aioobe    schedule 04.01.2013
comment
Да, именно так я понимаю это первое выражение в кавычках: даже если отслеживаемые блоки выполняются с измененным порядком, семантика не изменится при изолированном выполнении. Во втором утверждении говорится, что переход владения блокировкой происходит плавно. Я понимаю всю переупорядоченность следующим образом: переупорядочение связано только с семантикой. Блокировка не имеет плохого эффекта. Но переупорядочивание инструкций вызывает (даже более) неопределенное поведение при применении к коду, который использует общие переменные без какого-либо механизма блокировки.   -  person Sam    schedule 04.01.2013


Ответы (1)


Неофициально это запрещено. Это известно как «модель мотеля тараканов».

http://jeremymanson.blogspot.com/2007/05/roach-motels-and-java-memory-model.html

В частности, действие нельзя перемещать через блок синхронизации.

Однако формально JMM не говорит о переупорядочивании. В вашем примере мы можем только рассуждать так,

  1. либо блок синхронизации 1 находится перед блоком синхронизации 2 в общем порядке синхронизации, поэтому r2=A происходит — до A=2;r2 должно быть 0. Но между B=1 и r1=B нет ограничений; r1 может быть 0 или 1.

  2. или наоборот. r1 должно быть 0, r2 может быть 0 или 2.

Так что программа по-прежнему содержит гонку данных; тем не менее, мы можем сделать вывод, что (r1,r2) может быть только (0,0), (1,0), (0,2); невозможно быть (1,2)

person irreputable    schedule 03.01.2013