Является ли 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 ответу в следующем сообщении:

Volatile boolean vs AtomicBoolean

Ответ 5

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

Предположим, что у вас есть переменная i, которая является изменчивой, и ее значение зависит от другой изменчивой переменной say j. Теперь переменная доступа Thread-1 j и увеличит ее и собирается обновить ее в основной памяти из кэша CPU. В случае, если Thread-2 читает переменная я до того, как Thread-1 может фактически обновить j в основной памяти. Значение я будет соответствовать старому значению j, которое было бы неверным. Его также называют грязным.