Параллельный доступ к неизменяемой карте
@Singleton
@LocalBean
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class DeliverersHolderSingleton {
private volatile Map<String, Deliverer> deliverers;
@PostConstruct
private void init() {
Map<String, Deliverer> deliverersMod = new HashMap<>();
for (String delivererName : delivererNames) {
/*gettig deliverer by name*/
deliverersMod.put(delivererName, deliverer);
}
deliverers = Collections.unmodifiableMap(deliverersMod);
}
public Deliverer getDeliverer(String delivererName) {
return deliverers.get(delivererName);
}
@Schedule(minute="*", hour="*")
public void maintenance() {
init();
}
}
Синглтон используется для хранения данных. Данные обновляются раз в минуту. Возможно ли, что чтение из немодифицируемой карты будет проблемой с синхронизацией? Возможно ли, что произойдет переупорядочение в методе init, и ссылка на коллекцию будет опубликована, но коллекция заполнена не полностью?
3 ответа
Модель памяти Java гарантирует, что между записью и последующим чтением в энергозависимую переменную существует отношение " произойдет до". Другими словами, если вы записываете в переменную volatile и впоследствии читаете эту же переменную, у вас есть гарантия, что операция записи будет видимой, даже если задействовано несколько потоков:
Запись в энергозависимое поле (§8.3.1.4) происходит перед каждым последующим чтением этого поля.
Это идет дальше и гарантирует, что любая операция, которая произошла до операции записи, также будет видна в точке чтения (благодаря правилу упорядочения программы и тому факту, что отношение " происходит до" является транзитивным).
Ваш getDeliverers
Метод читает из переменной volatile, поэтому он будет видеть последнюю запись, выполненную в строке deliverers = Collections.unmodifiableMap(deliverersMod);
а также предыдущие операции, когда карта заполнена.
Таким образом, ваш код является потокобезопасным и ваш getDeliverers
Метод вернет результат, основанный на последней версии вашей карты.
В соответствии с сеткой переупорядочения, найденной здесь http://g.oswego.edu/dl/jmm/cookbook.html, первая операция Normal Store
не может быть переупорядочен с помощью второй операции Volatile Store
Таким образом, в вашем случае, если неизменяемая карта не равна нулю, проблем с переупорядочением не будет.
Кроме того, будут видны все записи, которые происходят до энергозависимого хранилища, поэтому вы не увидите никаких проблем с публикацией.
Вопросы безопасности темы здесь:
многократное чтение из HashMap - потокобезопасно, потому что допускается многократное чтение, если нет изменений в коллекции и записи в HashMap не произойдет, потому что карта является
unmodifiableMap()
читать / писать на
deliverers
- потокобезопасен, потому что все ссылки на Java являются атомарными
Я не вижу здесь операций, небезопасных для потоков.
Я хотел бы отметить, что имя init()
метод вводит в заблуждение, он предполагает, что он вызывается один раз во время инициализации; Я бы предложил позвонить rebuild()
или же recreate()
,