Java Memory Model взаимодействие синхронизации, энергозависимых и (штампованных) блокировок - PullRequest
0 голосов
/ 19 сентября 2018

Требуется ли модификатор volatile при работе с блокировками, чтобы гарантировать видимость памяти?

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

При приближении к главе jls 17.4.5 Я обнаружил:

Два действия могут быть упорядочены с помощью отношения «до того».Если одно действие происходит перед другим, то первое видно и упорядочено перед вторым.

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

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

В кратком коде

int field; //volatile not needed because we have a definite happens-before relationship
Lock lock;

void update(){
    //No matter how many threads access this method they will always have 
    //the most up to date field value to work with.
    lock.lock()
    field *= 2;
    lock.unlock();
}

Ответы [ 3 ]

0 голосов
/ 19 сентября 2018

... и фактически одна страница, в которой говорится, что синхронизированные методы и поля волатильности должны использоваться совместно.

Вы можете получить все, что вам нужно знать о видимости памяти и synchronizedблокирует до одного простого правила.То есть, что бы ни делал поток A с общими переменными и объектами до того, как он выходит из блока synchronized (o) {...}, он гарантированно станет видимым для потока B к тому времени, когда поток B входит в synchronized (o) {...} блок для того же объекта, o.

И, как уже говорилось в @markspace, любая реализация java.util.concurrent.locks.Lock должна работать таким же образом.

0 голосов
/ 20 сентября 2018

Требуется ли модификатор volatile при работе с блокировками, чтобы гарантировать видимость памяти? * Переменная

volatile гарантирует только видимость памяти, но не атомарность.Это одно из основных отличий между volatile и synchronized блоком в Java.Поэтому, когда вы используете synchronized блоков, переменные не обязательно должны быть volatile.Но если ваша переменная volatile и выполняет какие-либо составные действия с этой переменной, вам нужно защитить обновление переменной volatile с помощью блокировки.

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

Да.Потому что блокировки дадут вам и видимость, и атомарность.

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

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

0 голосов
/ 19 сентября 2018

Из документации API для Lock:

https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/locks/Lock.html

Все реализации Lock должны применять ту же семантику синхронизации памяти, что и встроенная блокировка монитора,как описано в главе 17 Спецификации языка Java ™:

  • Успешная операция блокировки имеет те же эффекты синхронизации памяти, что и успешное действие блокировки.
  • Успешная операция разблокировки имеет то же самоеэффекты синхронизации памяти как успешное действие разблокировки.

Неудачные операции блокировки и разблокировки и повторные операции блокировки / разблокировки не требуют каких-либо эффектов синхронизации памяти.

Это немного неясно, но суть в том, чточто да, Lock требуется для работы так же, как монитор (что делает ключевое слово synchronized), и поэтому в вашем примере всегда отображается последнее обновление field без явного использования ключевого слова volatile.

PS Получите Java-параллелизм Брайана Гетца на практике, он объясняет все эти вещи более подробно.По сути, это библия всех параллелизмов в Java.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...