Является ли volatile int
в Java потокобезопасным? То есть, можно ли безопасно читать и писать без блокировки?
Является ли volatile int в Java потокобезопасным?
Ответ 1
Да, вы можете прочитать его и безопасно записать в него, но вы не можете делать ничего такого, например, с его безопасным добавлением, так как это цикл чтения/изменения/записи. Там также вопрос о том, как он взаимодействует с доступом к другим переменным.
Точная природа изменчивости откровенно путается (см. раздел модель памяти в JLS для более подробной информации). Я лично использовал бы AtomicInteger
вместо этого, как более простой способ убедиться, что я прав.
Ответ 2
[...] как можно безопасно читать и писать без блокировки?
Да, чтение всегда приведет к значению последней записи, (и оба чтения и записи являются атомарными операциями).
Волатильное чтение/запись вводит в выполнение так называемое отношение before-before.
Из спецификации языка Java Глава 17: Потоки и блокировки
Записывается в нестабильное поле (§8.3.1.4) - перед каждым последующим чтением этого поля.
Другими словами, при работе с изменчивыми переменными вам не нужно явно синхронизировать (вводить связь "бывшее-до" ) с помощью ключевого слова synchronized
, чтобы гарантировать, что поток получает последнее значение, записанное в переменную.
Как отмечает Jon Skeet, использование изменчивых переменных ограничено, и вы должны, в общем случае, рассмотреть использование классов из пакета java.util.concurrent
.
Ответ 3
Доступ к volatile int в Java будет потокобезопасным. Когда я говорю о доступе, я имею в виду операцию блока над ним, например volatile_var = 10 или int temp = volatile_var (в основном, запись/чтение с постоянными значениями). Волатированное ключевое слово в java обеспечивает две вещи:
- При чтении вы всегда получаете значение в основной памяти. Как правило, для целей оптимизации JVM используют регистры или в более общих терминах локальные памяти для хранения/доступа переменных. Поэтому в многопоточной среде каждый поток может видеть другую копию переменной. Но, делая его изменчивым, убедитесь, что запись в переменную покраснели в основную память, и чтение ее также происходит из основной памяти и, следовательно, убедитесь, что поток видит в правой копии переменной.
- Доступ к энергозависимой памяти автоматически синхронизируется. Таким образом, JVM обеспечивает упорядочение при чтении/записи в переменную.
Однако Джон Скит правильно упоминает, что в неатомных операциях (volatile_var = volatile + 1) разные потоки могут получить неожиданный результат.
Ответ 4
Не всегда.
Это не потокобезопасно, если несколько потоков пишут и читают переменную. Это потокобезопасно, если у вас есть один поток писем и несколько потоков считывателей.
Если вы ищете безопасную тему, используйте AtomicXXX классы
Небольшой набор инструментов для классов, которые поддерживают незакрепленное потокобезопасное программирование для отдельных переменных.
По сути, классы в этом пакете расширяют понятие летучих значений, полей и элементов массива тем, которые также предоставляют операцию условного обновления атома формы:
boolean compareAndSet(expectedValue, updateValue);
Обратитесь к @teto ответу в следующем сообщении:
Ответ 5
Если волатильность не зависит от какой-либо другой изменчивой переменной, то ее поток безопасен для операции чтения. В случае записи volatile не гарантирует безопасность потока.
Предположим, что у вас есть переменная i, которая является изменчивой, и ее значение зависит от другой изменчивой переменной say j. Теперь переменная доступа Thread-1 j и увеличит ее и собирается обновить ее в основной памяти из кэша CPU. В случае, если Thread-2 читает переменная я до того, как Thread-1 может фактически обновить j в основной памяти. Значение я будет соответствовать старому значению j, которое было бы неверным. Его также называют грязным.