Search code examples
javaspring-bootconcurrencythread-safetyjava.util.concurrent

How to add a new element in case it does not exist in a ConcurrentMap while are using


I'm working on a Java development with threads and the truth is that I don't have much of an idea. It is being more complicated than I thought.

The thing is that I must group several objects in a ConcurrentMap, if the object is not in the ConcurrentMap must add it and otherwise modify it.

For the part of modifying the data I have no problems, but when I want to update I get a "Recursive update" error, I don't know what else I can do to modify/add my ConcurrentMap and make it threadSafe.

private final ConcurrentMap<String, Person> myData= new ConcurrentHashMap<>();

private void processMyData(){

 myData.compute(String, (key, person) -> {
        if (person== null) {
            myData.putIfAbsent(key, new Person("Antonio", 0, false));
        } else {
            //Update data, this part its ok!
            person.setConnectedHours(person.getConnectedHours() + 1000);
        }
        return person;
    });

}   

Solution

  • If the key doesn't exist, you just need to create a new person object and return it. ConcurrentMap#Compute will ensure that the entire invocation is atomic. If you call putIfAbsent when key does not exist inside compute, it will cause an infinite loop. (The infinite loop happens in ConcurrentHashMap#putVal method).

            myData.compute("A", (key, person) -> {
                if (person== null) {
                    person = new Person();
                } else {
                    //Update data, this part its ok!
    
                }
                return person;
            });
    

    See ConcurrentMap#compute JDK doc:

    Attempts to compute a mapping for the specified key and its current mapped value (or null if there is no current mapping). For example, to either create or append a String msg to a value mapping: map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))