Имеет ли пустая синхронизация (this){} какое-либо значение для видимости памяти между потоками?
Я прочитал это в поднятом голосовании комментарии на Stackru:
Но если вы хотите быть в безопасности, вы можете добавить простой синхронизированный (this) {} в конце вашего @PostConstruct [метод]
[обратите внимание, что переменные НЕ были изменчивыми]
Я думал, что произойдет, прежде чем принудительно, только если запись и чтение выполняется в synchronized
блок или, по крайней мере, чтение является изменчивым.
Верно ли цитируемое предложение? Делает пустой synchronized(this) {}
сбросить все переменные в текущем методе в "общедоступную" память?
Пожалуйста, рассмотрите некоторые сценарии
Что делать, если второй поток никогда не вызывает блокировки
this
? (предположим, что второй поток читает другими методами). Помните, что вопрос заключается в следующем: сбрасывать изменения в другие потоки, а не давать другим потокам способ (синхронизированный) опрашивать изменения, сделанные исходным потоком. Также отсутствие синхронизации в других методах очень вероятно в Spring@PostConstruct
контекст - как говорит оригинальный комментарий.видимость в памяти изменений вызвана только во втором и последующих вызовах другим потоком? (помните, что этот синхронизированный блок является последним вызовом в нашем методе) - это пометит этот способ синхронизации как очень плохую практику (устаревшие значения при первом вызове)
2 ответа
Все записи, которые происходят до monitor exit
видны всем темам после monitor enter
,
synchronized(this){}
можно превратить в байт-код, как
monitorenter
monitorexit
Так что, если у вас есть куча записей до synchronized(this){}
они произошли бы до monitorexit
,
Это подводит нас к следующему пункту моего первого предложения.
виден всем темам после
monitor enter
Так что теперь, чтобы поток гарантировал, что записи произошли, он должен выполнить ту же синхронизацию, т.е. synchornized(this){}
, Это выдаст как минимум monitorenter
и установить ваше происходит перед заказом.
Итак, чтобы ответить на ваш вопрос
Пустой синхронизированный (this) {} блок сбрасывает все переменные, измененные в текущем методе, в "общедоступную" память?
Да, если вы сохраняете ту же синхронизацию, когда хотите прочитать эти энергонезависимые переменные.
Чтобы ответить на другие ваши вопросы
Что делать, если второй поток никогда не вызывает блокировки на этом? (предположим, что второй поток читает другими методами). Помните, что вопрос заключается в следующем: сбрасывать изменения в другие потоки, а не давать другим потокам способ (синхронизированный) опрашивать изменения, сделанные исходным потоком. Также отсутствие синхронизации в других методах очень вероятно в контексте Spring @PostConstruct
Ну в этом случае с помощью synchronized(this)
без какого-либо другого контекста является относительно бесполезным. Отношения "до и после" не существует, и в теории они так же полезны, как и их отсутствие.
видимость в памяти изменений вызвана только во втором и последующих вызовах другим потоком? (помните, что этот синхронизированный блок является последним вызовом в нашем методе) - это пометит этот способ синхронизации как очень плохую практику (устаревшие значения при первом вызове)
Видимость памяти вызвана вызовом первого потока synchronized(this)
в том, что он будет писать прямо в память. Теперь это не обязательно означает, что каждый поток должен читать непосредственно из памяти. Они по-прежнему могут читать из своих собственных кеш-памяти процессора. Иметь вызов потока synchronized(this)
обеспечивает извлечение значения поля (полей) из памяти и получение наиболее актуального значения.
К сожалению, многое из того, что написано об этом в SO, включая многие ответы / комментарии в этой теме, неверно.
Ключевое правило в модели памяти Java, которое применяется здесь: операция разблокировки на данном мониторе происходит до последующей операции блокировки на этом же мониторе. Если только один поток когда-либо получает блокировку, это не имеет никакого значения. Если виртуальная машина может доказать, что объект блокировки ограничен потоком, она может исключить любые ограждения, которые она могла бы создать в противном случае.
Выделенная вами цитата предполагает, что снятие блокировки действует как полный забор. И иногда это может быть правдой, но вы не можете рассчитывать на это. Так что ваши скептические вопросы обоснованы.
См. Параллелизм Java на практике, гл. 16 для получения дополнительной информации о модели памяти Java.