Как понять «Переменная не участвует в инвариантах с другими переменными состояния при использовании ключевого слова volatile»? - PullRequest
10 голосов
/ 26 марта 2012

Из книги "Параллелизм Java на практике" стр. 26:

Вы можете использовать переменные переменные только при соблюдении всех следующих критериев:

  • Запись в переменнуюне зависит от его текущего значения, или вы можете гарантировать, что только один поток когда-либо обновит значение;

  • Переменная не участвует в инвариантах с другими переменными состояния;и

  • Блокировка не требуется по любой другой причине во время обращения к переменной.

Как понять " Переменная не участвует в инвариантах с другими переменными состояния при использовании ключевого слова volatile "?

1 Ответ

19 голосов
/ 26 марта 2012

Простое определение «инварианта»: условие, которое всегда верно в течение времени жизни объекта .

Изменчивые переменные не имеют общих свойств synchronized blocks.

Вот почему вы не можете использовать их в классе, имеющем инварианты, которые связаны с несколькими переменными.

Например, представьте, что у вас есть class для моделирования времениинтервал описывается двумя переменными: start и end.Инвариантным условием может быть то, что start всегда меньше или равно end.Если обе переменные (как в примере) объявлены как volatile, то вы можете положиться на функции видимости volatile, но вы не можете быть уверены, что во время изменения, которое включает обе переменные, инвариант всегда выполняется.Подумайте:

public void setInterval(Date newStart, Date newEnd)
{
 // Check if inputs are correct

 // Here the object state is valid
 start = newStart;

 // If another thread accesses this object now it will
 // see an invalid state because start could be greater than end

 end = newEnd;
 // Here the object state is valid again
}

В этом случае вы можете быть уверены, что изменение видимо для каждого потока, но в середине двух инструкций состояние объекта может быть недопустимым.Поскольку к нему могут обращаться другие потоки (помните, что это простой случай, поэтому он возможен, но маловероятен), тогда условие инварианта «начало <конец» может быть нарушено. </p>

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

  • Переменная не участвует в инвариантах, связанных с другими переменными (по причине, описанной выше).
  • Значениезапись в переменную не зависит от ее текущего значения.

Например, выражение int a = i++; не является атомарным, тогда оно, строго говоря, не является потокобезопасным, поскольку оно будет переписано примерно так:

int temp = i;
i = i + 1;
int a = temp;

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

public class MyAtomicInteger
{
  public synchronized increment()
  {
    x = x + 1;
  }

  private int x;
}

Конечно, существует истинная реализация этого AtomicInteger, и он является частью пакета java.util.concurrent.atomic , он предоставляет несколько простых базовых процедур для параллельного программирования без блокировок.

...