Волатильность и безопасность потоков в Java
Пожалуйста, возьмите этот очень простой пример:
volatile int globalVar = 1;
Моя тема:
if (globalVar > 0) {
globalVar--;
}
Теперь я должен решить, достаточно ли сделать переменную volatile, чтобы предотвратить состояние гонки и сделать этот поток безопасным.
Я знаю, что увеличивать и уменьшать нельзя, но я не уверен, отличается ли это от предыдущего условия.
Я думаю, что это все еще не безопасно, потому что это может быть выполнено в следующем порядке:
Поток А проверяет состояние. Поток B проверяет состояние. Шаг А увеличивается. Поток B увеличивается.
Я прав?
4 ответа
Ты прав. Это не потокобезопасность по той причине, что вы заявляете. volatile
гарантирует, что оба потока будут видеть обновленные значения переменной, но не защищает несколько строк кода.
Нет, это не безопасно. Летучий не гарантирует атомарность. Операции типа i-- не являются атомарными, поэтому объявление i как volatile не помогает.
int globalVar = 1;
lock.lock()
try{
if(globalVar > 0)
globalVar--;
}finally {
lock.unlock();
}
Приведенный выше код будет работать, вам не нужно объявлять golbalVar как volatile здесь, потому что
Volatile дает две гарантии:
1. Видимость 2. Изменение порядка
В то время как
Синхронизация / блокировка / разблокировка дают три гарантии 1. атомность 2. видимость 3. переупорядочение
Также помните, что когда объект совместно используется несколькими потоками, всегда обращайтесь к этому объекту при любых действиях синхронизации: синхронизация / произвольное чтение / запись.
Прочитайте Отличную статью здесь Автором Глава 17 JLS. Это необходимо прочитать http://jeremymanson.blogspot.in/2008/11/what-volatile-means-in-java.html http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html
Чтобы сделать ваш поток кода безопасным, вам нужно добавить synchronized
блок вокруг проверки и модификации.
Пример того, что можно сделать:
volatile Integer globalVar = 1;
Тогда в методе, который делает работу, вы можете:
synchronized public void decrement(){
if(globalVar > 0)
globalVar--;
}
}
volatile не гарантирует атомарность. Вы можете просто добавить синхронизированный блок.
synchronized(this)
{
if (globalVar > 0) {
globalVar--;
}
}