Я использую Spring с Redis и работаю со списком внутри хеша. Все отлично работает в одном потоке, возникают проблемы, когда мне приходится обновлять значение списка несколькими экземплярами.
Вот мой код для установки и получения значения из Hash:
public void put(String hashName, int key , List<myObj> myList) {
redis.opsForHash().put(hashName, String.valueOf(key), myList);
}
public List<myObj> get(String hashName, string key) {
Object map = redis.opsForHash().get(hashName,key);
if (map==null) {
log.info("no keys found");
return new ArrayList<myObj>();
}
List<myObj> myList= mapper.convertValue(map, new TypeReference<List<myObj>(){});
return myList;
}
Что я делаю, чтобы выполнить обновление:
List<myObj> myList= hash.get(hashName,key);
myList.add(obj);
hash.put(hashName, key, myList);
Когда есть больше чем один случай, я нахожусь в состоянии гонки. Есть ли способ обновить значения списка атомарным способом?
1 ответ
Ваша текущая реализация не подходит, потому что в put()
вы обновляете весь список. Если многие потоки хотят добавить один элемент в список, они сначала получают текущий список, затем добавляют элемент, а затем помещают новый список. Каждый поток отменяет результат предыдущего, последний побеждает. Использование synchronized
здесь не имеет значения.
< Сильный > Решение
Не заменяйте весь список. Вместо этого добавьте один элемент в список. Удалите метод put()
и добавьте новый, например:
public synchronized void add(String hashName, int key, myObj element) {
List<myObj> myList;
Object map = redis.opsForHash().get(hashName,key);
if (map != null) {
myList= mapper.convertValue(map, new TypeReference<List<myObj>(){});
} else {
myList = new ArrayList<myObj>();
}
myList.add(element);
redis.opsForHash().put(hashName, String.valueOf(key), myList);
}
Кроме того, убедитесь, что нет попыток изменить список напрямую и что единственный способ добавить элементы - это использовать ваш метод add()
. Используйте Collections.unmodifiableList()
:
public List<myObj> get(String hashName, string key) {
Object map = redis.opsForHash().get(hashName,key);
if (map==null) {
log.info("no keys found");
return new ArrayList<myObj>();
}
List<myObj> myList= mapper.convertValue(map, new TypeReference<List<myObj>(){});
return Collections.unmodifiableList(myList);
}
Похожие вопросы
Новые вопросы
java
Java - это язык программирования высокого уровня. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег редко используется отдельно и чаще всего используется вместе с [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] и [maven].