Как на самом деле работает volatile?

Пометка переменной как volatile в Java гарантирует, что каждый поток увидит последнее записанное в него значение вместо некоторого устаревшего значения. Мне было интересно, как это на самом деле достигается. Выдает ли JVM специальные инструкции, которые очищают кэш-память ЦП или что-то в этом роде?


person fredoverflow    schedule 22.04.2010    source источник
comment
Связанный вопрос (фактически первый в списке ..) stackoverflow.com/questions/1787450/   -  person BalusC    schedule 23.04.2010
comment
И ветку, которую я начал на volatile, с большим количеством голосов и фаворитов, касающихся выполнения вне очереди: stackoverflow.com/questions/2441279/   -  person SyntaxT3rr0r    schedule 23.04.2010


Ответы (2)


Насколько я понимаю, это всегда выглядит так, как будто кеш был очищен после записи, и всегда выглядит так, как будто чтение выполняется прямо из памяти при чтении. Эффект состоит в том, что поток всегда будет видеть результаты записи из другого потока и (согласно модели памяти Java) никогда не будет кэшированного значения. Однако фактическая реализация и инструкции ЦП будут отличаться от одной архитектуры к другой.

Это не гарантирует правильности, если вы увеличиваете переменную более чем в одном потоке или проверяете ее значение и предпринимаете какие-либо действия, поскольку, очевидно, нет фактической синхронизации. Как правило, вы можете гарантировать правильное выполнение только в том случае, если в переменную записывается только поток, а все остальные читают.

Также обратите внимание, что 64-битная НЕЛЕТУЧАЯ переменная может быть прочитана / записана как две 32-битные переменные, поэтому 32-битные переменные являются атомарными при записи, а 64-битные - нет. Одна половина может быть записана перед другой, так что прочитанное значение может быть не старым или новым.

Это довольно полезная страница из моих закладок:

http://www.cs.umd.edu/~pugh/java/memoryModel/

person gub    schedule 22.04.2010
comment
@jgubby: ваш последний абзац кажется неправильным: вы не можете прочитать 64-битный изменчивый файл, который будет иметь 32 бита от одной записи, а другой 32 бит от другой записи. - person SyntaxT3rr0r; 23.04.2010
comment
@WizardOfOdds: Согласен. Имеется в виду НЕ летучая переменная. - person gub; 23.04.2010
comment
@jbuggy: ай ай, вот что я подумал, но я не решился редактировать ваш пост, потому что я не был уверен, что вы имели в виду :) Рад помочь, иначе это немного сбивало с толку :))) - person SyntaxT3rr0r; 23.04.2010
comment
Наблюдение за записью другого потока зависит от отношения происходит до. Обновления tovolatiles не обязательно должны быть немедленными, если это не нарушает правила происходит до. Например, компилятор может объединить две записи в изменчивую переменную, если между ними не произойдет другого поведения "произошло раньше". - person Tom Hawtin - tackline; 02.11.2011

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

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

person Tom Hawtin - tackline    schedule 22.04.2010
comment
То, что происходит в правильно написанной программе на Java, не зависит от процессора. - person gub; 01.11.2011
comment
@jgubby Вопрос действительно спрашивает, выдаются ли особые инструкции. - person Tom Hawtin - tackline; 02.11.2011