Это выглядит небезопасно для меня.В частности, несинхронизированные вызовы будут в состоянии видеть частичные обновления, либо из-за видимости памяти (предыдущая позиция не была полностью опубликована, так как вы не сказали JMM, что это необходимо), либо из-за простой старой гонки.Представьте себе, если TroveMap.contains
имеет некоторую внутреннюю переменную, которая, как предполагается, не изменится в течение contains
.Этот код допускает разрыв этого инварианта.
Что касается видимости памяти, то проблема заключается не в ложных отрицаниях (для этого используется синхронизированная двойная проверка), но инварианты этого потока могут быть нарушены.Например, если у них есть счетчик, и они требуют, чтобы counter == someInternalArray.length
постоянно, нарушение синхронизации может нарушать это.
Моей первой мыслью было сделать ссылку на troveMap volatile
и повторно- пишите ссылку каждый раз, когда вы добавляете на карту:
synchronized (this) {
troveMap.put(key, value);
troveMap = troveMap;
}
Таким образом, вы устанавливаете барьер памяти таким образом, что любой, кто читает troveMap
, будет гарантированно видеть все, что произошлодо его самого последнего назначения - то есть его последнее состояние.Это решает проблемы с памятью, но не решает условия гонки.
В зависимости от того, насколько быстро изменяются ваши данные, может быть, фильтр Блума может помочь?Или какая-то другая структура, которая более оптимизирована для определенных быстрых путей?