Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I need to synchronize ConcurrentMap when adding key only if needed?

I have a ConcurrentMap<String, SomeObject> object. I want to write a method that would return the SomeObject value if it exists, or create a new SomeObject, put it in the Map, and return it if it doesn't exist.

Ideally, I could use ConcurrentMap's putIfAbsent(key, new SomeObject(key)), but that means that I create a new SomeObject(key) each time, which seems very wasteful.

So I resorted to the following code, but am not sure that it's the best way to handle this:

public SomeValue getSomevalue(String key){

  SomeValue result = concurrentMap.get(key);

  if (result != null)
    return result;

  synchronized(concurrentMap){

    SomeValue result = concurrentMap.get(key);

    if (result == null){
      result = new SomeValue(key);
      concurrentMap.put(key, result);
    }

    return result;
  }
}
like image 592
isapir Avatar asked Mar 13 '17 03:03

isapir


1 Answers

Ideally, I could use ConcurrentMap's putIfAbsent(key, new SomeObject(key)), but that means that I create a new SomeObject(key) each time, which seems very wasteful.

Then use computeIfAbsent:

concurrentMap.computeIfAbsent(key, SomeObject::new);

Using synchronized with a ConcurrentMap doesn't prevent other threads from performing operations on the map in the middle of the synchronized block. ConcurrentMap doesn't promise to use the map's monitor for synchronization, and neither ConcurrentHashMap nor ConcurrentSkipListMap synchronize on the map object.

Note that the ConcurrentMap interface doesn't promise that the value will only be computed once, or that the value won't be computed if the key is already present. ConcurrentHashMap makes these promises, but ConcurrentSkipListMap doesn't.

like image 65
user2357112 supports Monica Avatar answered Oct 15 '22 02:10

user2357112 supports Monica