Использование Java ReadWriteLock для синхронизации кэшированных данных - стоит ли помечать переменные состояния как энергозависимые?
Javadoc ReadWriteLock в Oracle и его реализация описывают, что делает блокировка и как ее использовать, но ничего не говорит о том, использовать ли блокировку. volatile
ключевое слово.
Это не тот же вопрос, что и do-all-mutable-variable-need-be-vol-volatile-когда-используя-блокировки, потому что я рад, что блокировка правильно синхронизирует доступ и видимость, но это использование volatile
для переменных все еще хорошая идея, например, для оптимизации компилятора или по каким-либо другим причинам?
Мои кэшированные данные состоят из редко измененных List
и несколько Maps
отображение объектов в списке с использованием различных атрибутов объектов.
private void reload() {
Set<Registration> newBeans = dao.listRegistered();
beans = Collections.unmodifiableSet(newBeans);
codeToBeanMap.clear();
userToBeanMap.clear();
nameToBeanMap.clear();
idToBeanMap.clear();
for (Registration bean : newBeans) {
codeToBeanMap.put(bean.getCode(), bean);
userToBeanMap.put(bean.getUser(), bean);
nameToBeanMap.put(bean.getName(), bean);
idToBeanMap.put(bean.getId(), bean);
}
}
Какие будут лучшие объявления? У меня есть это:
private Set<Registration> ecns;
private final Map<String, Registration> codeToBeanMap =
new HashMap<String, Registration>();
private final Map<String, Registration> userToBeanMap =
new HashMap<String, Registration>();
private final Map<String, Registration> nameToBeanMap =
new HashMap<String, Registration>();
private final Map<String, Registration> idToBeanMap =
new HashMap<String, Registration>();
3 ответа
Если вы собираетесь обращаться к переменной исключительно из кода, защищенного блокировкой, было бы излишним указывать эту переменную как volatile
и понесет определенный удар производительности (это в наносекундном диапазоне).
Ваши объявления, как это хорошо для параллелизма:
private final Map<String, Registration> idToBeanMap = new HashMap<>();
... потому что Java гарантирует, что поля, объявленные как final, будут инициализированы до того, как другие потоки смогут получить к ним доступ (по крайней мере, Java 1.5 и далее). Ключевое слово volatile не требуется (и в любом случае не имеет смысла для final).
Однако это ничего не говорит о содержимом HashMap - это не будет потокобезопасным, и разные потоки могут видеть различное или несовместимое содержимое, если вы не используете синхронизированные блоки кода. Самое простое решение - использовать ConcurrentHashMap. Это гарантирует, что все потоки увидят ожидаемое содержимое карты.
Однако это только означает, что операции на картах будут атомарными. В приведенном выше коде возможно, что вы очистили одну карту, но не другие (например) в тот момент, когда другой поток пытается прочитать данные, которые могут дать противоречивые результаты.
Таким образом, поскольку ваш код требует, чтобы несколько карт оставались синхронизированными и согласованными друг с другом, единственный способ - синхронизировать метод перезагрузки, а также заставить клиентов, считывающих данные, делать это через синхронизированный метод для одного и того же объекта.
но является ли использование volatile для переменных все еще хорошей идеей, например, для оптимизации компилятора или по каким-либо другим причинам?
Если что-то изменчивое, препятствует оптимизации компилятора, а не включает его
Javadoc ReadWriteLock в Oracle и его реализация описывают, что делает блокировка и как ее использовать, но ничего не говорят о том, использовать ли ключевое слово volatile.
Фактически, если вы посмотрите на интерфейсы, которые реализуют блокировки чтения и записи, в частности, интерфейс блокировки заявляет, что реализации должны обеспечивать те же гарантии видимости памяти, что и synchronized()
блок:
Все реализации Lock должны применять ту же семантику синхронизации памяти, которая предусмотрена встроенной блокировкой монитора, как описано в разделе 17.4 Спецификации языка Java™:
- Успешная операция блокировки имеет те же эффекты синхронизации памяти, что и успешное действие блокировки.
- Успешная операция разблокировки имеет те же эффекты синхронизации памяти, что и успешное действие разблокировки.