Простое определение «инварианта»: условие, которое всегда истинно в течение всего времени существования объекта.
Изменчивые переменные не обладают атомарными свойствами блоков synchronized
.
Вот почему вы не можете использовать их в классе, который имеет инварианты, связывающие несколько переменных.
Например, представьте, что у вас есть 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
}
В этом случае вы можете быть уверены, что изменение видно каждому потоку, но в середине двух инструкций состояние объекта может быть недействительным. Поскольку к нему могут обращаться другие потоки (помните, что это простой случай, так что это возможно, но маловероятно), то инвариантное условие «начало ‹ конец» может быть нарушено.
Вот почему использование 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, он предоставляет несколько простых базовых подпрограмм для параллельного программирования без блокировок.
person
Adriano Repetti
schedule
26.03.2012