Spring bean с сохранением состояния
Моему приложению на базе Spring фреймворка при инициализации необходимо инициализировать несколько бинов значениями из базы данных. Данные инициализируются в методе аннотируемом @PostConstruct. Существует несколько бинов приведенного ниже вида. Хранение данных в базе данных продиктовано тем что изменения могут быть в рантайме без перезагрузки приложения. Таким образом бины с сохранением состояния должны быть потокобезопасными. Проблема: есть бины где полей очень много и придется расписывать каждый геттер и сеттер и в последующем при внесении каких либо изменений получается есть вероятность чего то забыть. Вопрос насколько правильно реализована потокобезопасность и есть ли более правильное решение
public class GlobalProperties {
private String host;
private TimeZone timeZone;
private PropertiesService propertiesService;
private final Lock writeLock;
private final Lock readLock;
@Autowired
public GlobalProperties(PropertiesService propertiesService) {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
this.readLock = lock.readLock();
this.writeLock = lock.writeLock();
this.propertiesService = propertiesService;
}
public GlobalProperties() {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
this.readLock = lock.readLock();
this.writeLock = lock.writeLock();
}
@PostConstruct
public void init(){
updateProperty((GlobalProperties) propertiesService.getProperty(GlobalProperties.class));
}
public void updateProperty(GlobalProperties newProperty){
try {
writeLock.lock();
this.host = newProperty.getHost();
this.timeZone = newProperty.getTimeZone();
}finally {
writeLock.unlock();
}
}
public String getHost() {
try {
readLock.lock();
return host;
}finally {
readLock.unlock();
}
}
public TimeZone getTimeZone() {
try {
readLock.lock();
return this.timeZone;
}finally {
readLock.unlock();
}
}```
Ответы (1 шт):
Исключающая блокировка выглядит правильной, единственное, что я бы сохранял в поле ReentrantReadWriteLock, а read/writeLock брал непосредственно в методе (но это вкусовщина).
Окончательно убедиться в правильности реализации многопоточного кода можно с помощью JCStress. Вот этот пример вам подойдёт: https://github.com/openjdk/jcstress/blob/master/jcstress-samples/src/main/java/org/openjdk/jcstress/samples/primitives/mutex/Mutex_05_ReentrantLock.java
Также, если в вашем приложении host и timeZone соотносятся как ключ-значение, то вы можете реализовать эту же логику с помощью одного бина, содержащего ConcurrentHashMap<String, TimeZone>.