Неустойчивое ключевое слово безопасность потоков

После долгого поиска в Google я нашел несколько определений ключевого слова volatile.

Концепция 1:

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

Концепция 2:

Некоторые говорят, что это не потокобезопасно, так как вызывает состояние гонки потоков. Поскольку поток извлекает изменчивую переменную в пространство стека, изменяет ее и немедленно помещает обратно в основную память. Но в промежутке может прийти другой поток и воздействовать на изменчивую переменную и предпринять действия. Таким образом, некоторая ценность теряется.

Какая концепция верна?

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

yole 31.10.2018 13:56

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

Solomon Slow 31.10.2018 14:50
1
2
2 304
5

Ответы 5

concept 1 легко понять, но он неверен. volatile - это своего рода спецификация синхронизации, предоставляемая JMM, не о реализации. Кроме того, гарантия не может быть потокобезопасным ни при каких обстоятельствах.

Using volatile variables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable.

This means that changes to a volatile variable are always visible to other threads. What's more, it also means that when a thread reads a volatile variable, it sees not just the latest change to the volatile, but also the side effects of the code that led up the change.

Потокобезопасное использование:

1. int value = 1;
2. thread1 executes: value = 2;
3. when thread2 reads value, it must be 2

Небезопасное использование потока:

1. int value = 1;
2. thread1 executes: value++;
3. when thread2 reads value, it could be 1 or 2, because value++ is not atomic.

Эта статья IBM довольно хорошо резюмирует это:

Volatile variables share the visibility features of synchronized, but none of the atomicity features. This means that threads will automatically see the most up-to-date value for volatile variables. They can be used to provide thread safety, but only in a very restricted set of cases: those that do not impose constraints between multiple variables or between a variable's current value and its future values. So volatile alone is not strong enough to implement a counter, a mutex, or any class that has invariants that relate multiple variables (such as "start <=end").

Источник: https://www.ibm.com/developerworks/java/library/j-jtp06197/

Как-то связанный вопрос StackOverflow: Вы когда-нибудь использовали ключевое слово volatile в Java?

volatile сам по себе не является ни поточно, ни небезопасным.

volatile гарантирует атомарность для одного поля, и поэтому его можно использовать для однопотокового чтения или однопоточной записи.

Однако, если вы хотите выполнить поточно-ориентированную операцию, состоящую из чтения с последующей записью (понимаемой в целом), volatile сам по себе не обеспечивает потокобезопасность здесь, потому что volatile гарантирует атомарность только для отдельных операций (чтения или записи).

Подводить итоги:

  • если у вас есть поле, и вы хотите убедиться, что если один поток пишет в него, другие потоки могут немедленно прочитать записанное значение - volatile достаточно (без volatile другие потоки могут даже не увидеть записанное значение)
  • если у вас есть поле, которое вам нужно сначала прочитать, а только потом записать (на основе только что прочитанного значения, поэтому никакие операции с этим значением не могут происходить между ними), volatile недостаточно; вместо этого вы можете использовать:

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

  1. У потока может быть собственная копия значений ячеек памяти (вероятно, загруженная в реестр или кеш). при доступе к изменчивой переменной она всегда будет считываться из основной памяти.

  2. Компилятор java не изменяет порядок использования этих переменных (особенно из области синхронизации).

это означает, что для написания поточно-безопасного кода нам, возможно, придется использовать volatile, но простое использование volatile не приносит никакой пользы.

Вот что я понял после тщательного поиска в Google:

• Ключевое слово Volatile используется для предотвращения локальных копий переменной внутри потоков. Все потоки будут обращаться к изменчивой переменной из основной памяти, обновлять ее и сразу же помещать обратно в основной m / m.

С сайта ibm.com: Все операции чтения и записи будут производиться непосредственно в основной m / m, а не в регистры или кэш локального процессора.

• Изменяемая переменная не является потокобезопасной. Если несколько потоков пытаются записать в изменчивую переменную, возникает состояние Race.

• Каждый поток имеет отдельное пространство м / м, известное как рабочее м / м, оно содержит значение разницы. переменные для выполнения операций. После выполнения операции поток копирует обновленное значение переменной в главный m / m, и оттуда другие потоки могут считывать последнее значение. Но, если переменная энергонезависимая, новое значение не может быть немедленно сброшено в основной m / m. И другие потоки могут не прочитать обновленное значение.

• Синхронизация обеспечивает как взаимное исключение, так и видимость. Но volatile обеспечивает только видимость.

Другие вопросы по теме