Предпочитает синхронизировать с изменчивыми

Я прочитал этот ответ, в конце которого написано следующее:

Все, что вы можете с помощью volatile, может быть выполнено с синхронизацией, но а не наоборот.

Не понятно. JLS 8.3.1.4 определяет изменчивые поля следующим образом:

Поле может быть объявлено изменчивым, и в этом случае модель памяти Java гарантирует, что все потоки будут видеть согласованное значение для переменной (§17.4).

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

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

Ответ 1

Фактически синхронизация также связана с видимостью памяти, поскольку JVM добавляет барьер памяти в выходе синхронизированного блока. Это гарантирует, что результаты записи потоком в блоке синхронизации гарантированно будут видны при чтении другими потоками один раз, первый поток вышел из синхронизированного блока.

Примечание: после комментария @PaŭloEbermann, если другой поток проходит через бар для чтения (например, попадая в синхронизированный блок), их локальный кеш не будет признан недействительным, и поэтому они могут читать старое значение.

Выход из синхронизированного блока: происходит до в этом документе: http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility p >

Ищите эти выдержки:

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

и

Разблокировка (синхронизированный выход блока или метода) монитора происходит до каждой последующей блокировки (синхронизированный блок или метод запись) того же монитора. А так как отношение "бывает раньше" транзитивно, все действия нити перед разблокировкой произойти - перед всеми действиями после любой блокировки потока, которая монитор.

Ответ 2

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

Синхронизировано, чтобы убедиться, что только один поток будет обращаться к общему ресурсу в данный момент времени.

В то время как эти общие ресурсы часто объявляются как изменчивые, это связано с тем, что если поток изменил значение общего ресурса, он также должен обновиться и в другом потоке. Но без волатильности Runtime просто оптимизирует код, читая значение из кеша. Так что волатильность делает, всякий раз, когда любой поток доступ к volatile, он не будет читать значение из кеша, вместо этого он фактически получает его из фактической памяти, и тот же самый используется.


Проходил код log4j, и это то, что я нашел.

/**
 * Config should be consistent across threads.
 */
protected volatile PrivateConfig config;

Ответ 3

Это неправильно. Синхронизация связана с видимостью памяти. Каждый поток имеет собственный кеш. Если у вас есть блокировка, кеш обновляется. Если вы отпустите блокировку, кэш будет переведен в основную память.

Если вы читаете поле volatile, то также обновляется, если вы пишете поле volatile, есть флеш.

Ответ 4

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

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

Подробное руководство по volatile, см. 'volatile' не всегда достаточно.