2010-04-22 4 views
8

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

+0

Связанные вопрос (первый в списке на самом деле ..) http://stackoverflow.com/questions/1787450/how-do- i-understand-read-memory-барьеры-и-volatile – BalusC

+0

И нить, которую я начал с изменчивости с большим количеством «upvotes» и «фаворитов» относительно исполнения вне порядка: http://stackoverflow.com/questions/2441279/java-volatile-warranty-and-out-of-order-execution – SyntaxT3rr0r

ответ

8

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

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

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

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

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

+2

@jgubby: ваш последний абзац не кажется правильным: вы не можете прочитать 64-битную volatile, которая имела бы 32 бит от одной записи, а остальные 32 бит от другой записи. – SyntaxT3rr0r

+1

@WizardOfOdds: Согласен. Предположим, что там есть нелетучая переменная. – gubby

+0

@jbuggy: ах ах, вот что я подумал, но я не осмелился отредактировать ваш пост, потому что я не был уверен, что вы имели в виду :) Рад помочь, потому что в противном случае это было немного запутанно :))) – SyntaxT3rr0r

1

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

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

+1

То, что происходит в правильно написанной программе Java, не является специфичным для процессора. – gubby

+0

@jgubby Вопрос задает вопрос о том, испускаются ли специальные инструкции. –