Главная » Java » volatile Java

0

Обращение к любому элементу данных, допускающему изменение, со стороны различных потоков должно выполняться при условии синхронизации кода. использование механизмов синхронизации, однако, сопряжено с накладными расходами и не всегда удобно и целесообразно. Язык гарантирует, что операции чтения и записи любых значений, кроме относящихся к типам long или doublе, всегда выполняются атомарным образом - соответствующая переменная в любой момент времени будет содержать только то значение, которое сохранено определенным потоком, но не некую смесь результатов нескольких различных операций записи. Это значит, например, что доступ к атомарной переменной, в которую записывает данные только один поток и результатом пользуются другие потоки, не нуждается в защите посредством синхронизации кода, поскольку опасность взаимовлияния потоков отсутствует. Впрочем, эти соображения не применимы при реализации общей схемы действий "запросить изменить сохранить данные", когда синхронизировать код необходимо всегда.

Атомарный доступ не .гарантирует, что поток всегда сможет считать самую последнюю версию значения, сохраненного в переменной. Действительно, при отсутствии синхронизации вполне допустима ситуация, когда значение, записанное одним потоком, никогда не попадет в "поле зрения" другого потока. На возможность использования одним потоком значений переменной, записанных другим потоком, оказывает влияние множество различных факторов. Современное многопроцессорное аппаратное обеспечение зачастую демонстрирует странные особенности поведения, когда речь идет об обращении к данным в памяти, допускающим совместное использование. С точки зрения программиста подобные вещи не только странны – подчас они кажутся совершенно ничем не обоснованными и противоречащими исходному замыслу. Указанные особенности проявляются в том случае, если потоки обладают временной (рабочей) областью памяти, где значения переменных сохраняются и откуда считываются. Если не оговорено противное, компилятор способен работать исключительно с рабочей памятью и никогда не обращаться к основной области памяти переменной для чтения или обновления данных. Пусть, например, имеется значение, которое непрерывно отображается потоком, поддерживающим графический вывод, и это значение допускает изменение несинхронизированными методами; тогда код отображения может выглядеть следующим образом:

currentValue = 5;

for (;;) {

display.showValue(currentValue);

Thread.sleep(1000); // Вздремнуть на одну секунду

}

Если метод showValue сам по себе не обладает возможностью изменения значения currentValue, компилятор волен выдвинуть предположение о том, ЧТО внутри цикла for это значение можно трактовать как неизменное, и использовать одну и ту же константу 5 на каждой итерации цикла при вызове showValue. Но если содержимое поля currentValue в ходе выполнения цикла подвержено обновлению посредством других потоков, предположение компилятора окажется неверным.

Преодолеть проблему поможет соответствующим образом оформленный синхронизированный код – теперь компилятор не вправе руководствоваться собственным мнением относительно возможностей доступа к переменной и обязан при необходимости записи и считывания ее содержимого пользоваться только основной областью памяти переменной.

В отсутствие средств синхронизации существует альтернативный вариант решения проблемы – объявление поля можно снабдить модификатором volatilе. признак volatilе свидетельствует о том, что значение поля может быть изменено в любой непредсказуемый момент, и не позволяет компилятору пускаться в свободные "рассуждения". Если объявить currentValue как volatilе, компилятор будет вынужден, выполняя каждую итерацию цикла, заново перечитывать значение переменной. Метод, выполняющий считывание содержимого переменной, которая обозначена признаком volatil е, гарантированно возвращает наиболее свежую версию сохраненного в ней значения. Впрочем, если актуальность объектной ссылки гарантируется, это вовсе не значит, что и поля объекта, на который указывает эта ссылка, содержат самую последнюю информацию (признаком volatilе помечена ссылка, но не объект как таковой). Наконец, гарантии атомарности доступа можно распространить и на значения типа long и double, если снабдить их volatilе.

Источник: Арнолд, Кен, Гослинг, Джеймс, Холмс, Дэвид. Язык программирования Java. 3-е изд .. : Пер. с англ. – М. : Издательский дом «Вильяме», 2001. – 624 с. : ил. – Парал. тит. англ.

По теме:

  • Комментарии