Бывает-до и изменение порядка летучих - PullRequest
0 голосов
/ 07 января 2019

Существует несколько примеров кода, в которых предполагается, что следующие инструкции (1) и (2) не могут быть переупорядочены:

int value;
volatile boolean ready;

// ...

value = 1;     // (1)
ready = true;  // (2)

Последний ответ переполнения стека относится к JLS §17.4.5 :

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

Однако я не понимаю, почему это должно применяться здесь, поскольку JLS Пример 17.4-1 также заявляет:

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

, что здесь явно так.

Все другие определения в JLS, специфичные для volatile, относятся только к той же изменчивой переменной, но не к другим действиям:

Запись в энергозависимое поле (§8.3.1.4) происходит перед каждым последующим чтением этого поля.


Меня смущает, когда люди видят, что использование volatile (чтение или запись) не может быть изменено.

Не могли бы вы обосновать свое объяснение JLS или другими источниками, основанными на JLS.

1 Ответ

0 голосов
/ 29 января 2019

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

Если код двух потоков такой:

int value;
volatile boolean ready;

// Thread - 1
value = 1;     // (1)
ready = true;  // (2)

// Thread - 2
if (ready) {  // (3)
    x = value // (4)
}

Тогда между (1) и (2) мы имеем отношение «до и после» из-за программного порядка:

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

и между (2) и (3) мы имеем отношение «до и после» из-за изменчивости ready:

Запись в энергозависимое поле (§8.3.1.4) происходит - перед каждым последующим читать об этом поле.

И между (3) и (4) мы снова имеем отношение «до и после» из-за очередности программы:

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

Таким образом, существует цепочка «до того, как произойдет» (1) → (2), (2) → (3), (3) → (4)

И так как событие «до» - это транзитивное отношение (если «А» происходит до «В», а «В» - до «С», то «А» происходит до «С»), это означает, что (1) происходит до (4).

Если мы перевернем (3) и (4) так, чтобы второй поток прочитал value перед чтением ready, то произойдет разрыв цепи до того, как мы получим value .

Вот хороший учебник с еще несколькими подводными камнями JMM, включая этот.

Разве модель памяти Java не забавна?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...