2016-08-05 4 views
5

Рассмотрим фрагмент из Java Параллелизм на практике -Что произойдет, если переменная volatile будет записана из 2 потоков?

@ThreadSafe 
public class SynchronizedInteger{ 
    @GuardedBy("this") private int value; 

    public synchronized int getValue() { 
     return value; 
    } 

    public synchronized void setValue(int value) { 
     this.value = value; 
    } 
} 

Выписка из того же book-

Хороший способ думать о летучих переменных, чтобы представить себе, что они ведут себя примерно так класс SynchronizedInteger в листинге выше, , заменив чтение и запись изменчивой переменной на вызовы, чтобы получить и установить. Тем не менее доступ к изменчивой переменной не выполняет блокировки, поэтому не может вызвать блокировку исполняемого потока, что делает изменчивые переменные более сильным синхронизационным механизмом, чем синхронизированным.

Особый случай удержания резьбы применяется к переменным летучим. Безопасно выполнять операции чтения-изменения-записи по общим переменным волатильности, если вы гарантируете, что изменчивая переменная записывается только из одного потока.

Так что, если вы сделаете переменная экземпляра указанного класса летучим, а затем удалить синхронизированные ключевое слово, после этого предположим, что есть 3 темы

нитяным & Thread B Обращаемся к одной и той же изменчивой переменной ,
Резьба C считывает изменчивую переменную.

Поскольку переменная volatile теперь написана из 2 потоков, почему небезопасно выполнять операции чтения-изменения-записи этой общей изменчивой переменной?

ответ

2

Ключевое слово volatile используется для обеспечения того, чтобы изменения в вашем Object были видны другими Thread. Это не гарантирует, что неатомные операции на Object будут выполняться без вмешательства другого пользователя до завершения операции. Для обеспечения этого вам понадобится ключевое слово synchronized.

2

Это потому, что операции чтения-изменения-записи в переменных переменных не являются атомарными. v++ на самом деле что-то вроде:

r1 = v; 
r2 = r1 + 1; 
v = r2; 

Так что если у вас есть два потока, выполняющих эту операцию один раз, это могло привести к переменной инкрементируется только один раз, так как они оба читают старое значение. Это пример того, почему это не безопасно.

В вашем примере было бы небезопасно, если бы вы удалили синхронизацию, сделали поле volatile и имели два потока, вызывающих setValue после некоторой условной логики, основанной на возврате getValue - это значение могло быть изменено другим потоком.

Если вы хотите, чтобы атомные операции рассматривались в пакете java.util.concurrent.atomic.

1

Если вы записываете переменную volatile из нескольких потоков без использования каких-либо синхронизированных конструкций, вы обязаны получить ошибки несогласованности данных.

Используйте переменные volatile без синхронизации в случае одиночной записи и нескольких потоков чтения для атомных операций.

Volatile убедитесь, что значение переменной выбрано из основной памяти вместо Thread cache. Он безопасен для использования в случае операций с одиночной записью и множественным чтением.

Используйте Атомные переменные или синхронизацию или API блокировки для обновления и чтения переменных из нескольких потоков.

Обратитесь к соответствующей SE вопрос:

What is meant by "thread-safe" code?

Смежные вопросы