﻿# V6074\. Non\-atomic modification of volatile variable\.

Анализатор обнаружил неатомарное изменение 'volatile' переменной, которое может привести к состоянию гонки\.  

Известно, что использование модификатора 'volatile' гарантирует, что все потоки будут видеть актуальное значение соответствующей переменной\. К этому можно добавить, что модификатор 'volatile' используется для того, чтобы указать JVM, что все операции присвоения этой переменной и все операции чтения из неё должны быть атомарными\.

Можно посчитать, что пометки переменных как 'volatile' будет достаточно, чтобы безопасно их использовать в многопоточном приложении\! Но что будет, если изменять 'volatile' переменную, будущее значение которой зависит от текущего?

К таким операциям можно отнести:

* var\+\+, \-\-var, \.\.\.
* var \+\= smt, var \*\= smt, \.\.\. 
* \.\.\.

Рассмотрим использование 'volatile' переменной в качестве счетчика \(counter\+\+\)\. 

```cpp
class Counter
{
  private volatile int counter = 0;
  ....
  public void increment()
  {
    counter++; // counter = counter + 1
  }
  ....
}
```

Такая операция выглядит как одна операция, но в действительности это целая последовательность операций чтения\-изменения\-записи\. Здесь и кроется состояние гонки\. 

Предположим, что 2 потока одновременно работают с объектом класса Counter и выполняют инкремент переменной 'counter' \(10\):

\[counter \=\= 10, temp \=\= 10\] Поток N1 считывает значение 'counter'во временную переменную\.

\[counter \=\= 10, temp \=\= 11\] Поток N1 изменяет временную переменную\.

\[counter \=\= 10, temp \=\= 10\] Поток N2 считывает значение 'counter'во временную переменную\.

\[counter \=\= 11, temp \=\= 11\] Поток N1 записывает временную переменную в 'counter'\.

\[counter \=\= 11, temp \=\= 11\] Поток N2 изменяет временную переменную\.

\[counter \=\= 11, temp \=\= 11\] Поток N2 записывает временную переменную в 'counter'\.

Ожидалось значение переменной 'counter' равное 12 \(а не 11\), так как 2 потока выполнили инкремент над одной и той же переменной\. Также возможна ситуация, когда потоки выполнят инкремент друг за другом, и в таком случае все будет так, как и ожидалось\. Как итог, раз на раз не приходится\!

Чтобы избежать подобного поведения неатомарных операций для разделяемых переменных, можно использовать:

* Блок 'synchronized',
* Классы из пакета java\.util\.concurrent\.atomic,
* Функциональность блокировок из пакета java\.util\.concurrent\.locks

Пример корректного кода:

```cpp
class Counter
{
  private volatile int counter = 0;
  ....
  public synchronized void increment()
  {
    counter++;
  }
  ....
}
```

или

```cpp
class Counter
{
  private final AtomicInteger counter = new AtomicInteger(0);
  ....
  public void increment()
  {
    counter.incrementAndGet();
  }
  ....
}
```