В книге Java Concurrency In Practice нам говорят несколько раз, что инструкции нашей программы могут быть переупорядочены либо компилятором, либо JVM во время выполнения, либо даже процессор. Поэтому мы должны предположить, что исполняемая программа не будет выполнять свои инструкции в точно таком же порядке, чем указано в исходном коде.Инструкции по переупорядочиванию и произошедшие до отношения в java
Тем не менее, в последней главе, посвященной Java-модели памяти, содержится список , предшествующий правилам, указывающим, какое упорядочение инструкций сохраняется JVM. Первое из этих правил:
- «Порядок выполнения программы. Каждое действие в потоке происходит перед каждым действием в этом потоке, которое приходит позже в порядке выполнения программы».
Я считаю, что «порядок программы» относится к исходному коду.
Мой вопрос: при условии, что это правило, мне интересно, какая инструкция может быть переупорядочена.
«Действие» определяются следующим образом:
модели памяти Java определяются в терминах действий, которые включают в себя чтение и запись переменных, и снятия мониторов, а также запуск и стыковку с нитями. JMM определяет частичное упорядочение, которое происходит раньше, для всех действий внутри программы. Чтобы гарантировать, что действие, выполняющее поток B, может видеть результаты действия A (независимо от того, происходят ли A или B в разных потоках), должно произойти до отношения между A и B. В случае отсутствия события перед заказом между двумя операций, JVM может свободно переупорядочивать их по своему усмотрению.
Другие правила порядка являются упоминалось: правило блокировки
- Monitor. Разблокировка блокировки монитора происходит до каждой последующей блокировки на той же самой блокировке монитора.
- Неустойчивое правило переменной. Запись в изменчивое поле происходит до каждого последующего чтения этого же поля.
- Правило начала темы. Вызов Thread.start в потоке происходит перед каждым действием в запущенном потоке.
- Правило прекращения нити. Любое действие в потоке происходит до того, как какой-либо другой поток обнаружит, что поток завершился, либо успешно вернуться из Thread.join, либо Thread.isAlive возвращает false.
- Прерывание правило. Прерывание потока, вызываемое другим потоком, происходит до того, как прерываемый поток обнаружит прерывание (либо с вызовом InterruptedException, либо вызовом isInterrupted или прервано).
- Правило финализатора. Конец конструктора объекта происходит до начала финализатора для этого объекта.
- Транзитивность. Если А происходит до B, и B происходит до С, то А происходит до С.
спасибо. Но все еще что-то не хватает: если правило порядка программы действительно выполняется, тогда y всегда следует назначать после x в T1 независимо от «перспективы» (T1 или T2), не так ли? Таким образом, T2 всегда должен отображать соответствующее значение x. Пример, который вы предоставляете, определенно правдивый, я скорее обсуждаю правильность правила правила программы сам по себе («Каждое действие в потоке происходит до каждого действия в этом потоке, которое приходит позже в порядке программы»). – Martin
@ Мартин указывает на то, что _happens-before_ является лишь частичным порядком - в то время как 'x = 5' _happens-before_' y = 6' из-за правила порядка программы, отношения _happens-before_ вообще отсутствуют между любым из этих инструкции и все, что происходит в T2, так что нормально, чтобы T2 мог видеть результат 'y = 6', но не результат' x = 5'.Если 'y' были volatile, то это обеспечило бы связь _happens-before_ между' y = 6' в T1 и 'if (y == 6)' в T2 в том смысле, что _if_ T2 видит 'y = 6' _then_ it должен также видеть 'x = 5'. –