Маркировка переменной как volatile
в Java гарантирует, что каждый поток видит значение, которое было в последний раз написано для него, а не какое-то устаревшее значение. Мне было интересно, как это реально достигается. Является ли JVM специальными инструкциями, которые скрывают процессорные деньги или что-то в этом роде?Как работает volatile?
ответ
Из того, что я понимаю, всегда кажется, что кеш был сброшен после записи и всегда выглядит так, как будто чтение читается прямо из памяти при чтении. Эффект заключается в том, что Thread всегда будет видеть результаты записи из другого потока и (в соответствии с моделью памяти Java) никогда не кэшировать значение. Фактические инструкции по реализации и ЦП будут меняться от одной архитектуры к другой.
Это не гарантирует правильность, если вы увеличиваете переменную более чем в одном потоке или проверяете ее значение и предпринимаете некоторые действия, поскольку, очевидно, фактическая синхронизация отсутствует. Обычно вы можете гарантировать только правильное выполнение, если только переменная Thread записывается в переменную, а другие все читают.
Также обратите внимание, что 64-битная нелетучая переменная может быть прочитана/записана как две 32-битные переменные, поэтому 32-битные переменные являются атомарными для записи, но 64-разрядные - нет. Одна половина может быть написана перед другой - поэтому прочитанное значение может быть ниже старого или нового значения.
Это довольно полезная страница из моих закладок:
@jgubby: ваш последний абзац не кажется правильным: вы не можете прочитать 64-битную volatile, которая имела бы 32 бит от одной записи, а остальные 32 бит от другой записи. – SyntaxT3rr0r
@WizardOfOdds: Согласен. Предположим, что там есть нелетучая переменная. – gubby
@jbuggy: ах ах, вот что я подумал, но я не осмелился отредактировать ваш пост, потому что я не был уверен, что вы имели в виду :) Рад помочь, потому что в противном случае это было немного запутанно :))) – SyntaxT3rr0r
То, что происходит, зависит от процессора. Как правило, есть некоторые инструкции по защите памяти. Очевидно, что очистка всего кеша будет очень дорого - в аппаратном обеспечении есть протоколы когерентности кэша.
Также важно, чтобы определенные оптимизации не выполнялись через доступ к полю. Компилятор имеет важное значение при рассмотрении многопоточности, а не просто думать об аппаратном обеспечении.
То, что происходит в правильно написанной программе Java, не является специфичным для процессора. – gubby
@jgubby Вопрос задает вопрос о том, испускаются ли специальные инструкции. –
Связанные вопрос (первый в списке на самом деле ..) http://stackoverflow.com/questions/1787450/how-do- i-understand-read-memory-барьеры-и-volatile – BalusC
И нить, которую я начал с изменчивости с большим количеством «upvotes» и «фаворитов» относительно исполнения вне порядка: http://stackoverflow.com/questions/2441279/java-volatile-warranty-and-out-of-order-execution – SyntaxT3rr0r