let's say I have a spring service
@Service
class SomeClass {
private ConcurrentHashMap<String, List<SomeItem>> map;
// key is not null, item is not null
public void addSmth(String key, SomeItem item){
emptyMap(key);
List<SomeItem> list = Collections.synchronizedList(new ArrayList<>());
if(map.containsKey(key)) {
list = map.get(key);
list.add(item);
} else {
list.add(item);
map.put(key, list);
}
}
// will remove some entries, check if row is empty and if so: remove the key
private void emptyMap(key) {
List<SomeItem> list = map.get(key);
if(list != null) {
List<SomeItem> collect = new ArrayList<SomeItem>();
list.forEach(i -> {
// basically if element in the list is smaller than one value, I left out the details to make it readable here
if(i.isSmaller(some_value)) {
collect.add(i);
}
});
list.removeAll(collect);
if(list.isEmpty()) {
map.remove(key);
}
}
}
}
This looks good on first sight but I thought about it and since containsKey
and get
on the map is not atomic, running this might possibly cause a NullPointerException on list.add(item)
since it might be possible that another thread entered map.remove(key)
in the emptyMap
function when addSmth
is invoked concurrently. So my question is:
Is this a race condition in spring boot? I know that Spring uses Tomcat with multiple threads so it should be a problem! And how do I reproduce such an exception (in Tests with Spring). I know I could technically just rewrite it to fix the problem but I'm interested in the reproduction of this! (If it is even an issue)
Many thanks.