«Запись в изменчивое поле (§8.3.1.4) происходит перед каждым последующим чтением этого поля».
Итак, я знаю, что volatile поле можно использовать для синхронизации, чтобы гарантировать, что вся информация, которая есть у потока 1 до записи в volatile поле, будет видна потоку 2 после чтения этого volatile.
Но как насчет последующих записей? Поведение такое же? Любая помощь приветствуется, ничего не могу найти об этом в официальных документах.
Примеры:
### Write -> Read
#Thread1 (Write)
xxx = "anyValue" - any variable with value before volatile
boolean volatile b = true
#Thread2 (Read)
if (b) { -> here we read volatile value
print(xxx) -> guaranteed visibility of 'xxx' 100%, will print 100% "anyValue"
}
### Write -> Write
#Thread1 (Write)
xxx = "anyValue" - any variable with value before volatile
boolean volatile b = true;
#Thread2 (Write)
b = false; -> here we write to volatile value
print(xxx); -> guaranteed visibility of 'xxx'???, what will be printed?
«xxx» не является логическим значением, это просто любой объект, который был изменен или установлен в Thread1, и мне интересно, предоставит ли запись в ту же изменчивую переменную доступ к этим данным для другого Thread2. В случае чтения это 100%, а про последующие ничего не пишет :(
Вы не правы, когда вы читаете volatile поле, все данные, которые были доступны для потока писателя, становятся доступными для потока читателя: jeremymanson.blogspot.com/2008/11/…
«[Я] ничего не могу найти об этом в официальных документах». - Все это указано в главе 17 JLS. Да, читается непросто... но если вы собираетесь писать код, зависящий от volatile для синхронизации, то в этом надо разбираться. И наоборот, если вы не можете понять, что говорит JLS, вам не следует пытаться выполнять синхронизацию таким образом. (Используйте примитивы параллелизма более высокого уровня. В подавляющем большинстве случаев синхронизация без блокировки не требуется.)
Спасибо за ваш комментарий. Я прочитал его еще раз и нашел те же блоки текста. Запись в изменчивую переменную v (§8.3.1.4) синхронизируется со всеми последующими операциями чтения v любым потоком (где «последующий» определяется в соответствии с порядком синхронизации). И это: запись в изменчивое поле (§8.3.1.4) происходит перед каждым последующим чтением этого поля. Так что никакой информации о последующих записях... может я просто слепой(
Ну... в нем не упоминаются последующие записи потоком A, потому что последующие записи не имеют связанных гарантий. Спецификация JMM посвящена тому, что >гарантировано<. Он не перечисляет (и не должен) бесконечное множество негарантированных вещей. Если что-то не заявлено как гарантированное, то оно не гарантируется.
Как я уже сказал, спецификацию нелегко читать... но вся информация есть. И если вам слишком сложно рассуждать о том, что указано (и не указано) в спецификации, не стоит пытаться делать умные вещи с volatile. ИМО.
Возможно, вы правы. И я до сих пор не готов к таким вещам. Но все равно большое спасибо за уточнение правильного ответа на мой вопрос!
Чтобы дать немного более полный ответ, построив отношение «происходит до» из его основных порядков:
Порядок синхронизации: это общий порядок всех действий синхронизации. Поскольку запись в энергозависимую память является действием синхронизации, 2 записи в энергозависимую память в одни и те же или разные переменные являются частью порядка синхронизации. Порядок синхронизации будет даже порядка, например. блокировка A и изменчивое чтение B, потому что это полный порядок.
Синхронизируется с порядком. Это частичный заказ, который заказывает только определенные действия синхронизации. Например, снятие блокировки со всеми последующими захватами этой же блокировки, записью volatile-переменной и всеми последующими операциями чтения этой переменной. Таким образом, 2 изменчивые записи в разные или одни и те же переменные не упорядочены по порядку синхронизации.
Порядок программы: проще говоря, это порядок, указанный в коде программы. В вашем случае записи 2 volatile не упорядочены по порядку программы, поскольку они выдаются разными потоками.
Теперь мы подходим к последнему шагу: отношению «происходит раньше», которое является порядком. Это транзитивное замыкание объединения порядка программы и порядка синхронизируется с.
Таким образом, несмотря на то, что 2 энергозависимые записи являются частью порядка синхронизации, они не являются частью порядка синхронизации с, и, как следствие, они не являются частью порядка «происходит до». Таким образом, они не вызывают никаких событий до краев.
Я добавил несколько примеров, может быть, это прояснит, о чем я говорю, поэтому вы можете дать более точный ответ. Но все равно спасибо за ответ)