Изменчивые переменные Java, влияющие на согласованность памяти других энергонезависимых переменных

Сценарий А

A1. Написать в переменную

A2. Сбросить все локальные энергонезависимые переменные записи в основную память

Сценарий Б

B1. Чтение из изменчивой переменной

БИ 2. Перезагрузить все энергонезависимые переменные из основной памяти в локальную память

  • Являются ли сценарии A и B правильным поведением, связанным с изменчивыми переменными? Или сценарий A также включает B2, или сценарий B также включает A2?
  • Являются ли эти сценарии атомарными? Что-нибудь еще может случиться между А1 и А2? Или B1 и B2?

(используя Java 1.8 / 1.5+)

2 ответа

Решение

Запись в энергозависимые переменные не гарантирует сброс энергонезависимых переменных 1. Тем не менее, он введет отношение "происходит раньше" между записью в volatile и любым последующим чтением volatile (при условии, что в него не было внесено никаких промежуточных записей). Вы можете использовать это следующим образом:

  1. Тема A: напишите NV
  2. Тема A: напишите V
  3. Тема B: читать V
  4. Тема B: читать NV

Если действия выполняются в таком порядке, то поток B увидит обновленное значение NV на шаге 4. Однако, если что-то (включая A) записывает в NV после шага 2, неизвестно, что поток B увидит на шаге 4.

В целом, использование летучих веществ таким способом требует глубоких и тщательных рассуждений. Это проще и надежнее в использовании synchronized,


Ваш пример неясен:

  • Если это предназначено для описания того, что должен делать программист на Java, это неправильно / бессмысленно. Java-код не может сбрасывать переменные.

  • Если предполагается, что это спецификация того, что должно происходить на уровне реализации (например, в скомпилированном коде JIT), это также неправильно.

  • Если предполагается, что это описание того, что может произойти на уровне реализации (например, в скомпилированном коде JIT), это правильно.

Я не просто педантичен здесь. Компилятор может решить, что ему не нужно сбрасывать все локальные энергонезависимые компоненты в потоке A, и он, скорее всего, перезагрузит только те, которые ему нужны в потоке B. Как он решит? Это дело авторов компиляторов!


1 - JLS не требует специальных аппаратных операций, таких как сброс. Вместо этого он требует, чтобы скомпилированный код соответствовал некоторым конкретным гарантиям видимости памяти, и оставляет реализацию за разработчиком компилятора.

Фактическое правило: "Запись в энергозависимую переменную v (§8.3.1.4) синхронизируется со всеми последующими чтениями v любым потоком (где" последующий "определяется в соответствии с порядком синхронизации)". http://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html

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

Я не уверен, что "промывка на главную" - это необходимый способ понять это. Модель памяти Java задокументирована с точки зрения " происходит раньше" и синхронизируется с ней. Я рекомендую думать об этом в этих терминах. Концептуально JVM может пропустить определенные "сбросы", если они не нужны для обещания.

Другие вопросы по тегам