Re[3]: вопрос по блокировке
От: ekamaloff Великобритания  
Дата: 13.02.12 10:36
Оценка: 18 (1)
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, ekamaloff, Вы писали:


E>>Если я правильно понял, то операции определенные в данном классе уже синхронизированы, т.е. не требует какой-либо дополнительной блокировки со стороны вызывающего кода. В таком случае разве недостаточно сделать переменную, которая хранит ссылку на текущий экземпляр volatile? В таком случае блокировки для получения данной ссылки не требуется.


PD>Вот это я не совсем понимаю. volatile гарантирует, что изменения будут видны другим потокам, то есть что другие потоки не сохранят у себя копии, а должны будут читать из оригинала каждый раз. Это замечательно, но какое отношение это имеет к блокировке ? Чтение переменнной volatile обязательно идет в одну команду ?


Грубо говоря volatile гарантирует что обновленное значение переменной будет немедленно видно другим потокам. Упрощенное объяснение и пример можно найти здесь, а более формальное определение семантики volatile в контексте "порядка синхронизации" в секции 17.4.4 здесь (англ.):

A write to a volatile variable (§8.3.1.4) v synchronizes-with all subsequent reads of v by any thread (where subsequent is defined according to the synchronization order).

Запись volatile переменной v синхронизирована-с последующими чтениями v любым потоком (где "последующий" определено в контексте "порядка синхронизации")


Кроме того, независимо от того, является ли переменная volatile или нет, запись и чтение переменной ссылочного типа в Java — атомарная операция (это справедливо и для примитивных типов). Как бы ни конкурировали с собой потоки в вашем приложении, у вас всегда есть гарантия того, что переменная содержит либо null или валидную ссылку на объект (без volatile эта переменная может быть устаревшей локальной копией и может вести к непредсказуемым последствиям относительно видимого порядка выполнения некоторых операций — см. пример по первой ссылке выше).

Блокировка при чтении и записи (используя synchronized или java.util.concurrent.lock.*) — это в вашей ситуации альтернатива volatile, которая имеет более сложную семантику:
  1. Обеспечивает немедленное обновления значения переменной во всех потоках (подобно volatile)
  2. Обеспечивает семантику happens-before (так же как и volatile, по-моему начиная с версии 5)
  3. Обеспечивает взаимо-исключающее (мьютекс) выполнение данного участка кода разными потоками

В вашей задаче реально требуется только (1), (2) по большому счету не нужно и в любом случае обеспечивается volatile, (3) — лишнее и может значительно ухудшить производительность кода.


PD>Поток A начинает читать переменную. Считывает ее на регистр X.

PD>Поток B изменяет переменную
PD>Поток A заканчивает чтение , засылая из регистра X в регистр Y.

Как я сказал выше — чтение и запись ссылочной переменной атомарны (это не связано с volatile). Как только поток A считал переменную в локальный стек, его больше не должно волновать что произойдет с исходной volatile переменной.
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.