В спецификации языка Java нет атомарных операций для операторов ++
и --
.Другими словами, когда вы пишете код следующим образом:
a++;
компилятор Java фактически выдает код, который похож на набор шагов, приведенных ниже (фактические инструкции могут различаться в зависимости от характера переменной):
- Загрузите операнд в стек, используя одну из операций для
load
ввода данных. - Дублируйте значение операнда в стеке (с целью возвратапотом).Обычно это выполняется с помощью операции
dup
. - Увеличивает значение в стеке.Обычно выполняется с помощью операции
iadd
в ВМ. - Возвращает значение (полученное на шаге 2).
Как вы можете заметить, в ВМ есть несколько операций длячто обычно считается атомной операцией.ВМ может обеспечить атомарность только до уровня отдельной операции.Любое дальнейшее требование может быть достигнуто только с помощью синхронизации или других методов.
Использование ключевого слова volatile
позволяет другим потокам получать самое последнее значение переменной;все операции чтения переменной будут возвращать недавно обновленное значение для каждой инструкции.Например, если переменная a
должна быть энергозависимой в предыдущем примере, то поток, считывающий значение a
, будет видеть другие значения, если он будет читать a
после инструкции 2 и после инструкции 3. Использованиеvolatile
не защищает от этого сценария.Он защищает от сценария, когда несколько потоков видят несколько значений для a
после инструкции 2 (например).