Подтвердить что ты не робот

Переупорядочение инструкции и происходит до отношений в java

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

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

  • "Правило порядка программы. Каждое действие в потоке происходит перед каждым действием в этом потоке, которое приходит позже в порядке выполнения программы.

Я считаю, что "порядок программы" относится к исходному коду.

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

"Действие" определяется следующим образом:

Модель памяти Java задается с точки зрения действий, которые включают в себя чтение и запись в переменные, блокировки и разблокировки мониторов, а также запуск и соединение с потоками. JMM определяет частичное упорядочение, которое происходит раньше, для всех действий внутри программы. Чтобы гарантировать, что действие, выполняющее поток B, может видеть результаты действия A (независимо от того, происходят ли A или B в разных потоках), должно произойти до отношения между A и B. В случае отсутствия события перед заказом между двумя операции, JVM может свободно переупорядочивать их по своему усмотрению.

Другие упомянутые правила заказа:

  • Правило блокировки монитора. Блокировка блокировки монитора происходит до каждой последующей блокировки на той же самой блокировке монитора.
  • Изменчивое правило. Запись в поле volatile происходит до каждого последующего чтения этого же поля.
  • Правило начала темы. Вызов Thread.start в потоке происходит перед каждым действием в запущенном потоке.
  • Правило завершения строки. Любое действие в потоке происходит до того, как какой-либо другой поток обнаружит, что поток завершен, либо успешно возвратиться из Thread.join, либо Thread.isAlive, возвращающий false.
  • Правило прерывания. Прерывание прерывания потока в другом потоке происходит до того, как прерываемый поток обнаружит прерывание (либо с вызовом InterruptedException, либо вызовом isInterrupted или прервано).
  • Правило финализатора. Конец конструктора для объекта происходит до начала финализатора для этого объекта.
  • транзитивность. Если A происходит до B, а B - до C, то A происходит до C.
4b9b3361

Ответ 1

Ключевой момент правила порядка программы: в потоке.

Представьте эту простую программу (все переменные изначально 0):

Т1:

x = 5;
y = 6;

Т2:

if (y == 6) System.out.println(x);

С точки зрения T1 выполнение должно быть согласовано с назначением y после x (порядок программы). Однако с точки зрения T2 это не обязательно, и T2 может печатать 0.

T1 фактически разрешено назначать y сначала, поскольку 2 присваивания являются независимыми, а их замена не влияет на выполнение T1.

При правильной синхронизации T2 всегда будет печатать 5 или ничего.

ИЗМЕНИТЬ

Вы, кажется, неправильно истолковываете смысл порядка программы. Правило порядка программы сводится к:

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

бывает-раньше имеет очень специфическое значение в JMM. В частности, это не означает, что y=6 должен быть после x=5 в T1 с точки зрения настенных часов. Это означает, что последовательность действий, выполняемых T1, должна соответствовать этому порядку. Вы также можете обратиться к JLS 17.4.5:

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

В приведенном выше примере вы согласитесь, что с точки зрения T1 (т.е. в одной программе с резьбой) x=5;y=6; согласуется с y=6;x=5;, так как вы не читаете значения. Утверждение на следующей строке гарантируется в T1, чтобы увидеть эти 2 действия, независимо от того, в каком порядке они выполнялись.