Class Future
{
private volatile boolean ready;
private Object data;
public Object get()
{
if(!ready) return null;
return data;
}
public synchronized void setOnce(Object o)
{
if(ready) throw...;
data = o;
ready = true;
}
}
В нем говорилось, что "если поток читает данные, от записи к чтению существует преждевременный переход, который гарантирует видимость данных".
Из своего обучения я знаю:
- volatile гарантирует, что каждое чтение / запись будет происходить в памяти, а не только в кеше или регистрах;
- volatile обеспечивает переупорядочение: то есть в методе setOnce () data = o может быть запланировано только после if (ready) throw ... и до ready = true; это гарантия того, что если в get () ready = true, данные должны быть отключены.
Мое замешательство
возможно ли, что когда поток 1 находится в setOnce (), достигнет точки после data = o; до готовности = истина; В то же время поток 2 запускает get (), готовность к чтению ложна и возвращает ноль. И thead 1 продолжает готово = правда. В этом сценарии поток 2 не видел новых «данных», хотя данным было присвоено новое значение в потоке 1.
get () не синхронизируется, это означает, что синхронизированная блокировка не может защитить setOnce (), поскольку поток 1 вызывает get (), которому не нужно получать блокировку для доступа к готовой переменной, data. Таким образом, потоку не гарантируется, что оно увидит последнее значение данных. Под этим я подразумеваю, что блокировка гарантирует только видимость между синхронизированными блоками. Несмотря на то, что один поток выполняет синхронизированный блок setOnce (), другой поток все еще может перейти в get () и получить доступ к готовым и данным без блокировки и может увидеть старое значение этих переменных.
в get (), если ready = true, данные должны быть o? Я имею в виду, что эта ветка гарантированно увидит видимость данных? Я думаю, что данные не являются изменчивыми и не синхронизируются с get (). Может ли этот поток видеть старое значение в кеше?
Спасибо!
1
в основном ложный. Ключевое словоvolatile
имеет отношение к видимости памяти, а не кэшам. Кеши обрабатываются оборудованием когерентности кеша. И это был бы явно ужасный дизайн, который никто бы не использовал - память слишком медленная, чтобы использовать ее таким образом. - person David Schwartz   schedule 11.11.2015volatile
не имеет никакого отношения к этим кешам. Доступ кvolatile
может оставаться полностью в кэше L1 без проблем. (К сожалению, статья, на которую вы ссылаетесь, повторяет миф.) - person David Schwartz   schedule 11.11.2015volatile
отключает), не имеет ничего общего с кешами ЦП. (Это действительно то, что действительно понимают очень, очень немногие люди.) - person David Schwartz   schedule 11.11.2015volatile
. У некоторых ЦП есть буферы предварительной выборки или буферы записи, которые скрывают что-то от других процессоров, иvolatile
их нужно обойти. - person David Schwartz   schedule 11.11.2015