Подтвердить что ты не робот

Имеет ли пустая синхронизация (это) {} какое-либо значение для видимости памяти между потоками?

Я прочитал это в предыдущем комментарии к StackOverflow:

Но если вы хотите быть в безопасности, вы можете добавить простой синхронизированный (это) {} в конце вашего @PostConstruct [method]

[обратите внимание, что переменные НЕ были волатильными]

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

Правильно ли цитируется предложение? Описан ли пустой блок synchronized(this) {} всех переменных, измененных в текущем методе, на "общую видимую" память?

Пожалуйста, рассмотрите некоторые сценарии

  • что если второй поток никогда не вызывает блокировку на this? (предположим, что второй поток читается другими способами). Помните, что этот вопрос касается: сброса изменений в другие потоки, а не , чтобы другие потоки (синхронизировались) влияли на опрос изменений, сделанных исходным потоком. Также отсутствие синхронизации в других методах очень вероятно в контексте Spring @PostConstruct, как говорится в оригинальном комментарии.

  • - видимость памяти изменений, вызванных только во втором и последующих вызовах другим потоком? (помните, что этот синхронизированный блок является последним вызовом в нашем методе) - это означало бы такой способ синхронизации как очень плохую практику (устаревшие значения при первом вызове)

4b9b3361

Ответ 1

Все записи, которые происходят до monitor exit, видны для всех потоков после monitor enter.

A synchronized(this){} можно преобразовать в байт-код, например

monitorenter
monitorexit

Итак, если у вас есть куча записей до synchronized(this){}, они должны были произойти до monitorexit.

Это подводит нас к следующему пункту моего первого предложения.

видна для всех потоков после monitor enter

Итак, теперь для того, чтобы поток обеспечивал выполнение записи, он должен выполнить ту же синхронизацию, то есть synchornized(this){}. Это приведет к по меньшей мере a monitorenter и установит, что вы делаете это до заказа.


Итак, чтобы ответить на ваш вопрос

Выполняется ли пустая синхронизированная (эта) {} блокировка всех переменных в текущем методе "общая видимая" память?

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

Для решения других вопросов

что, если вторая нить никогда не вызывает блокировку? (предположим, что второе нить читается другими способами). Помните, что речь идет о: flush изменения в другие потоки, не дают другим потокам путь (синхронизированный) для опроса изменений, сделанных исходной нитью. Также отсутствие синхронизации в другие методы очень вероятны в контексте Spring @PostConstruct

В этом случае использование synchronized(this) без какого-либо другого контекста относительно бесполезно. Существует не бывает - до отношения, и это теоретически так же полезно, как и не включать его.

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

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

Ответ 2

Большая часть того, что написано об этом на SO, включая многие ответы/комментарии в этом потоке, к сожалению, неверно.

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

Цитата, которую вы выделяете, предполагает, что освобождение блокировки действует как полный забор. И иногда это может быть правдой, но вы не можете рассчитывать на это. Поэтому ваши скептические вопросы являются обоснованными.

См. Java Concurrency на практике, Ch 16 для получения дополнительной информации о модели памяти Java.