Подтвердить что ты не робот

Изменчивая переменная в Java

Итак, я читаю эту книгу под названием Java Concurrency на практике, и я застрял в этом одном объяснении, которое я, похоже, не могу понять без примера. Это цитата:

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

Может ли кто-нибудь дать мне контрпример из-за того, почему "значения переменных ALL, которые были видны до A до записи в изменчивую переменную, становятся видимыми для B ПОСЛЕ прочтения изменчивой переменной"?

Я смущен, почему все остальные энергонезависимые переменные не становятся видимыми для B перед чтением изменчивой переменной?

4b9b3361

Ответ 1

В потоке B может быть локальный кэш ЦП этих переменных. Чтение изменчивой переменной гарантирует, что какой-либо промежуточный кеш-флеш от предыдущей записи до летучего наблюдается.

В качестве примера прочитайте следующую ссылку, которая завершается с помощью "Фиксация блокировки с двойной проверкой с использованием летучего":

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

Ответ 2

Объявление изменчивой переменной Java означает:

  • Значение этой переменной никогда не будет кэшироваться нить-локально: все чтения и записи будут переходить прямо к "основной памяти".
  • Доступ к переменной действует так, как если бы она была заключена в синхронизированный блок, синхронизированный сам по себе.

Как раз для вашей справки, когда требуется летучесть?

Когда несколько потоков используют один и тот же переменная, каждая нить будет иметь собственной копии локального кеша для этого переменная. Поэтому, когда он обновляет значение, оно фактически обновляется в локальный кеш не входит в основную переменную Память. Другой поток, который использование той же переменной не знает ничего о значениях, измененных другой поток. Чтобы избежать этого проблема, если вы объявите переменную как летучий, то он не будет сохранен в локальном кеше. Всякий раз, когда поток обновляют значения, обновляются к основной памяти. Итак, другие потоки может получить доступ к обновленному значению.

От JLS §17.4.7 Хорошо сформированные казни

Мы рассматриваем только хорошо сформированные казни. Выполнение E = < P, A, po, поэтому W, V, sw, hb > хорошо сформирован если выполняются следующие условия:

  • Каждый прочитанный видит, что запись в тот же переменная в исполнении. Все прочитанные и пишет об изменчивых переменных неустойчивые действия. Для всех чтений r в A, имеем W (r) в и W (r).v = r.v. Переменная r.v является неустойчивой, если и только если r - неустойчивое чтение, а переменная w.v является изменчивой, если и только если w - неустойчивая запись.

  • Случается, что перед порядком является частичным заказ. Бывает - до заказа транзитивным замыканием синхронизирует - с ребрами и программой заказ. Он должен быть действительным частичным порядок: рефлексивный, транзитивный и антисимметричен.

  • Выполняется выполнение внутрипоточная согласованность. Для каждого поток t, действия, выполняемые t в такие же, как и генерируемый этим потоком в программный порядок в изоляции, причем каждый напишите, записывая значение V (w), заданное что каждый прочитанный r видит значение В (Ш (г)). Значения, отображаемые каждым определяемой моделью памяти. указанный приказ программы должен отражать порядок программы, в котором действия будет выполняться в соответствии с внутрипоточная семантика P.

  • Выполнение выполняется - до согласованного (§17.4.6).

  • Выполняется выполнение согласованность последовательности синхронизации. Для все изменчивые чтения r в A, это не случай, когда либо (r, W (r)), либо что существует выигрыш A для записи что w.v = r.v и поэтому (W (r), w) и так что (w, r).

Полезная ссылка: Что мы действительно знаем о неблокировании concurrency в Java?

Ответ 3

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

Если переменная объявлена ​​волатильной, то компилятор больше не пытается оптимизировать обращения (чтение и запись) к этой переменной. Тем не менее, он может продолжать оптимизировать доступ для других переменных.

Во время выполнения, когда доступна изменчивая переменная, JVM генерирует соответствующие инструкции по защите памяти для CPU. Потенциал памяти служит той же цели - процессор также не позволяет переупорядочить инструкции.

Когда переменная volatile записывается в (по потоку A), все записи в любую другую переменную завершаются (или будут по крайней мере кажутся) и становятся видимыми для A перед записью в изменчивую переменную; это часто связано с инструкцией по записи памяти-записи. Аналогично, любые чтения других переменных будут завершены (или будут отображаться) до читать (по потоку B); это часто связано с инструкцией по считыванию памяти. Это упорядочение инструкций, которые выполняются барьером (-ами), будет означать, что все записи, видимые для A, будут видны B. Это, однако, не означает, что никакого повторного упорядочения инструкций не произошло (возможно, компилятор выполнил переупорядочение для других инструкций); это просто означает, что если какие-либо записи, видимые для A, произошли, это будет видно B. В более простых терминах это означает, что порядок строгой программы не поддерживается.

Я укажу на эту запись на Memory Barriers и JVM Concurrency, если вы хотите понять, как JVM выдает инструкции по защите памяти, более подробно.

Связанные вопросы

Ответ 4

В потоках разрешено кэшировать значения переменных, которые другие потоки могут обновлять с момента их чтения. Ключевое слово volatile заставляет все потоки не кэшировать значения.

Ответ 5

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

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

Если вы использовали переменную volatile, как только поток B считывает из нее некоторое значение X, VM гарантирует, что все, что поток A написал до того, как он написал X, также видны B. (И также все, что A получил гарантированный как видимый, транзитный).

Аналогичные гарантии предоставляются для синхронизированных блоков и других типов замков.