volatile
имеет семантику для видимости памяти. По существу, значение volatile
поля становится видимым для всех читателей (в частности, для других потоков) после завершения операции записи в него. Без volatile
, читатели могли видеть не обновленную ценность.
Чтобы ответить на ваш вопрос: Да, я использую volatile
переменную, чтобы контролировать, продолжает ли какой-либо код цикл. Цикл проверяет volatile
значение и продолжается, если оно есть true
. Условие может быть установлено false
путем вызова метода «stop». Цикл видит false
и завершает работу, когда проверяет значение после завершения выполнения метода stop.
Книга « Параллелизм Java на практике », которую я очень рекомендую, дает хорошее объяснение volatile
. Эта книга написана тем же человеком, который написал статью IBM, на которую есть ссылка в этом вопросе (фактически, он цитирует свою книгу в нижней части этой статьи). Я использую volatile
то, что его статья называет «флагом статуса шаблона 1».
Если вы хотите узнать больше о том, как volatile
работает тайник, ознакомьтесь с моделью памяти Java . Если вы хотите выйти за пределы этого уровня, посмотрите хорошую книгу по компьютерной архитектуре, такую как Hennessy & Patterson, и прочитайте о согласованности и согласованности кэша.
volatile
которое появилось в новой модели памяти Java, определенной в JSR 133: когда поток читаетvolatile
переменную, он видит не только значение, записанное в него последним другим потоком, но также все другие записи в другие переменные, которые были видны в этом другом потоке во времяvolatile
записи. Смотрите этот ответ и эту ссылку .«… Модификатор volatile гарантирует, что любой поток, который читает поле, увидит последнее записанное значение». - Джош Блох
Если вы думаете об использовании
volatile
, прочитайте о пакете,java.util.concurrent
который имеет дело с атомарным поведением.Сообщение Википедии о паттерне Singleton показывает изменчивость в использовании.
источник
volatile
иsynchronized
ключевые слова?volatile
примеров. Его можно найти в архивной версии .void
и другоеpublic
».Важный момент о
volatile
:synchronized
иvolatile
и замки.synchronized
переменную. Использованиеsynchronized
ключевого слова с переменной недопустимо и приведет к ошибке компиляции. Вместо использованияsynchronized
переменной в Java вы можете использоватьvolatile
переменную java , которая будет указывать потокам JVM считывать значениеvolatile
переменной из основной памяти и не кэшировать ее локально.volatile
ключевое слово не нужно .источник
Пример использования
volatile
:Мы создаем экземпляр лениво во время первого запроса.
Если мы не создадим
_instance
переменную,volatile
то Поток, создающий экземпляр,Singleton
не сможет связаться с другим потоком. Таким образом, если поток A создает экземпляр Singleton и сразу после создания процессор испортит и т. Д., Все остальные потоки не смогут увидеть значение_instance
как не нулевое, и они будут считать, что ему по-прежнему присваивается значение null.Почему это происходит? Поскольку потоки считывателя не делают никакой блокировки, и пока поток записывающего устройства не выйдет из синхронизированного блока, память не будет синхронизирована и значение
_instance
не будет обновлено в основной памяти. С ключевым словом Volatile в Java это обрабатывается самой Java, и такие обновления будут видны всем потокам читателей.Пример использования без volatile:
Код выше не является потокобезопасным. Хотя он проверяет значение экземпляра еще раз в синхронизированном блоке (по соображениям производительности), JIT-компилятор может переставить байт-код таким образом, чтобы ссылка на экземпляр была установлена до того, как конструктор завершит свое выполнение. Это означает, что метод getInstance () возвращает объект, который, возможно, не был полностью инициализирован. Чтобы сделать код потокобезопасным, ключевое слово volatile может использоваться начиная с Java 5 для переменной экземпляра. Переменные, помеченные как volatile, становятся видимыми для других потоков только после того, как конструктор объекта полностью завершит свое выполнение.
Источник
volatile
использование в Java :Отказоустойчивые итераторы обычно реализуются с использованием
volatile
счетчика объекта списка.Iterator
создается, текущее значение счетчика внедряется вIterator
объект.Iterator
операция выполняется, метод сравнивает два значения счетчика и выдает a,ConcurrentModificationException
если они различны.Реализация отказоустойчивых итераторов обычно легка. Они обычно полагаются на свойства структур данных конкретной реализации списка. Там нет общей картины.
источник
private static final Singleton _instance;
также.volatile
очень полезно останавливать темы.Не то чтобы вы писали свои собственные потоки, в Java 1.6 есть много хороших пулов потоков. Но если вы уверены, что вам нужна нить, вам нужно знать, как ее остановить.
Шаблон, который я использую для потоков:
В приведенном выше сегменте кода чтение потока
close
в цикле while отличается от вызывающегоclose()
. Без volatile поток, выполняющий цикл, может никогда не увидеть изменения, чтобы закрыться.Обратите внимание, что нет необходимости в синхронизации
источник
volatile
ключевого слова, и всегда кажется, что он работает нормально.Одним из распространенных примеров использования
volatile
является использованиеvolatile boolean
переменной в качестве флага для завершения потока. Если вы создали поток и хотите иметь возможность безопасно прервать его из другого потока, вы можете периодически проверять флаг. Чтобы остановить это, установите флаг в true. Установив флагvolatile
, вы можете убедиться, что поток, который его проверяет, увидит, что он установлен, в следующий раз, когда он проверяет его, даже не используяsynchronized
блок.источник
Переменная, объявленная с
volatile
ключевым словом, имеет два основных качества, которые делают ее особенной.Если у нас есть переменная volatile, она не может быть кэширована в кэш-память компьютера (микропроцессора) никаким потоком. Доступ всегда происходил из основной памяти.
Если есть операция записи, выполняющая изменчивую переменную, и внезапно запрашивается операция чтения , гарантируется, что операция записи будет завершена до операции чтения .
Два вышеперечисленных качества выводят, что
А с другой стороны,
volatile
ключевое слово является идеальным способом для поддержки совместно используемой переменной, которая имеет «n» число потоков чтения и только один поток записи для доступа к ней. Как только мы добавимvolatile
ключевое слово, все готово. Никаких других накладных расходов на безопасность потоков.Conversly,
Мы не можем использовать
volatile
ключевое слово исключительно, чтобы удовлетворить общую переменную, которая имеет доступ к нескольким потокам записи .источник
Никто не упомянул обработку операций чтения и записи для длинных и двойных переменных. Чтение и запись - это атомарные операции для ссылочных переменных и большинства примитивных переменных, за исключением типов переменных long и double, которые должны использовать ключевое слово volatile для атомарных операций. @ссылка на сайт
источник
Да, volatile должно использоваться всякий раз, когда вы хотите, чтобы изменяемая переменная была доступна нескольким потокам. Это не очень распространенный вариант использования, потому что обычно вам нужно выполнить более одной атомарной операции (например, проверить состояние переменной перед ее изменением), и в этом случае вместо этого вы будете использовать синхронизированный блок.
источник
На мой взгляд, есть два важных сценария, кроме остановки потока, в котором используется ключевое слово volatile:
источник
Вам нужно будет использовать ключевое слово «volatile» или «синхронизированный» и любые другие инструменты и методы управления параллелизмом, которые могут быть в вашем распоряжении, если вы разрабатываете многопоточное приложение. Примером такого приложения являются настольные приложения.
Если вы разрабатываете приложение, которое будет развернуто на сервере приложений (Tomcat, JBoss AS, Glassfish и т. Д.), Вам не придется самостоятельно управлять параллелизмом, поскольку это уже решено сервером приложений. На самом деле, если я правильно помню, стандарт Java EE запрещает какой-либо контроль параллелизма в сервлетах и EJB-компонентах, поскольку он является частью уровня «инфраструктуры», который, как вы предполагали, был освобожден от его обработки. Вы можете управлять параллелизмом только в таком приложении, если реализуете одноэлементные объекты. Это даже уже решено, если вы связываете свои компоненты, используя frameworkd, как Spring.
Таким образом, в большинстве случаев разработки Java, когда приложение является веб-приложением и использует IoC-фреймворк, такой как Spring или EJB, вам не нужно использовать 'volatile'.
источник
volatile
только гарантирует, что все потоки, даже сами по себе, увеличиваются. Например: счетчик видит одну и ту же грань переменной одновременно. Он не используется вместо синхронизированных, атомарных или других вещей, он полностью синхронизирует чтение. Пожалуйста, не сравнивайте его с другими ключевыми словами Java. Как показано в примере ниже, операции с переменными переменными также являются атомарными, они терпят неудачу или завершаются сразу.Даже если вы поставили изменчивый или нет результаты всегда будут отличаться. Но если вы используете AtomicInteger, как показано ниже, результаты будут всегда одинаковыми. Это то же самое с синхронизированным также.
источник
Да, я использую это довольно часто - это может быть очень полезно для многопоточного кода. Статья, на которую вы указали, хорошая. Хотя следует помнить о двух важных вещах:
источник
Каждый поток, обращающийся к изменчивому полю, будет читать свое текущее значение перед продолжением, вместо (потенциально) использования кэшированного значения.
Только переменная-член может быть изменчивой или переходной.
источник
Абсолютно да. (И не только в Java, но и в C #.) Есть моменты, когда вам нужно получить или установить значение, которое гарантированно будет атомарной операцией на вашей данной платформе, например, int или boolean, но не требует накладные расходы на блокировку резьбы. Ключевое слово volatile позволяет вам убедиться, что при чтении значения вы получаете текущее значение, а не кэшированное значение, которое просто устарело при записи в другой поток.
источник
Существует два различных использования ключевого слова volatile.
Флаг занятости используются , чтобы предотвратить поток от продолжения в то время как устройство занято , и флаг не защищен замком:
Поток тестирования продолжится, когда другой поток отключит флаг занятости :
Однако, поскольку в потоке тестирования часто осуществляется доступ к занятому объекту, JVM может оптимизировать тест, поместив значение занятости в регистр, а затем протестировать содержимое регистра, не считывая значение занятости в памяти перед каждым тестом. Поток тестирования никогда не увидит изменения занятости, а другой поток только изменит значение занятости в памяти, что приведет к взаимоблокировке. Объявление флага занятости как volatile заставляет его значение считываться перед каждым тестом.
Использование энергозависимых переменных снижает риск ошибок согласованности памяти , поскольку любая запись в энергозависимую переменную устанавливает отношение «происходит до» с последующим чтением этой же переменной. Это означает, что изменения в изменчивой переменной всегда видны другим потокам.
Техника чтения, записи без ошибок согласованности памяти называется атомарным действием. .
Атомное действие - это то, что эффективно происходит одновременно. Атомное действие не может остановиться в середине: оно либо происходит полностью, либо вообще не происходит. Никакие побочные эффекты атомного действия не видны, пока действие не завершено.
Ниже приведены действия, которые можно указать как атомарные:
Ура!
источник
volatile
говорит программисту, что значение всегда будет актуальным. Проблема в том, что значение может быть сохранено на разных типах аппаратной памяти. Например, это могут быть регистры ЦП, кэш-память ЦП, ОЗУ ... регистры ЦП и кэш-память ЦП принадлежат ЦП и не могут совместно использовать данные в отличие от ОЗУ, которое находится на выручке в многопоточном окружении.volatile
Ключевое слово говорит, что переменная будет читаться и записываться из / в оперативную память напрямую . Имеет некоторый объем вычисленийJava 5
продленvolatile
путем поддержкиhappens-before
[О]volatile
Ключевое слово не лечит вrace condition
ситуацию , когда несколько потоков могут написать несколько значений одновременно. Ответ являетсяsynchronized
ключевым словом [О]В результате безопасность только тогда, когда один поток пишет, а другие просто читают
volatile
значениеэнергозависимый и синхронизированный
источник
Летучий делает следующее.
1> Чтение и запись изменчивых переменных различными потоками всегда осуществляется из памяти, а не из собственного кэша потока или регистра процессора. Таким образом, каждый поток всегда имеет дело с последним значением. 2> Когда 2 разных потока работают с одним и тем же экземпляром или статическими переменными в куче, один может видеть действия других как вышедшие из строя. Смотрите блог Джереми Мэнсона по этому вопросу. Но изменчивый помогает здесь.
Следующий полностью исполняемый код показывает, как несколько потоков могут выполняться в предопределенном порядке и печатать выходные данные без использования синхронизированного ключевого слова.
Для достижения этой цели мы можем использовать следующий полноценный работающий код.
Следующая ссылка на github содержит файл readme, который дает правильное объяснение. https://github.com/sankar4git/volatile_thread_ordering
источник
На странице документации оракула возникает необходимость в энергозависимой переменной для решения проблем с согласованностью памяти:
Это означает, что изменения в
volatile
переменной всегда видны другим потокам. Это также означает, что когда поток читает изменчивую переменную, он видит не только последние измененияvolatile
, но и побочные эффекты кода, который привел к изменению.Как объяснено в
Peter Parker
ответе, в отсутствиеvolatile
модификатора стек каждого потока может иметь свою собственную копию переменной. Делая переменную какvolatile
, проблемы согласованности памяти были исправлены.Взгляните на страницу учебника jenkov для лучшего понимания.
Взгляните на связанный вопрос SE для получения более подробной информации о volatile и вариантах использования volatile:
Разница между изменчивым и синхронизированным в Java
Один практический пример использования:
У вас есть много потоков, которые необходимо напечатать текущее время в определенном формате, например:
java.text.SimpleDateFormat("HH-mm-ss")
. У Yon может быть один класс, который конвертирует текущее время вSimpleDateFormat
переменную и обновляет ее каждую секунду. Все остальные потоки могут просто использовать эту переменную для печати текущего времени в файлах журнала.источник
Изменчивые переменные - легкая синхронизация. Когда требование последних данных среди всех потоков является требованием и атомарность может быть скомпрометирована, в таких ситуациях предпочтительнее использовать изменчивые переменные. Чтение по переменным переменным всегда возвращает самую последнюю запись, выполненную любым потоком, поскольку они не кэшируются ни в регистрах, ни в кэшах, где другие процессоры не могут видеть. Летучий - без блокировки. Я использую volatile, когда сценарий соответствует критериям, указанным выше.
источник
Ключ volatile при использовании с переменной будет гарантировать, что потоки, читающие эту переменную, увидят одно и то же значение. Теперь, если у вас есть несколько потоков, читающих и записывающих переменную, сделать переменную volatile будет недостаточно, и данные будут повреждены. Потоки изображений прочитали одно и то же значение, но каждый из них выполнил некоторые изменения (скажем, увеличил счетчик), при обратной записи в память целостность данных нарушается. Вот почему необходимо сделать переменную синхронизированной (возможны разные пути)
Если изменения выполняются одним потоком, а остальным нужно просто прочитать это значение, подойдет volatile.
источник
переменная volatile в основном используется для мгновенного обновления (сброса) в основной строке общего кэша после его обновления, чтобы изменения немедленно отражались на всех рабочих потоках.
источник
Ниже приведен очень простой код для демонстрации требования
volatile
к переменной, которая используется для управления выполнением потока из другого потока (это один из сценариев, гдеvolatile
это требуется).Когда
volatile
не используется: вы никогда не увидите сообщение « Stopped on: xxx » даже после « Stopping on: xxx », и программа продолжит работу.При
volatile
использовании: вы увидите « Остановлено: ххх » немедленно.Демо: https://repl.it/repls/SilverAgonizingObjectcode
источник