Search code examples
javamultithreadingconcurrencyjava.util.concurrent

Looking for concurrent map with functors



If I look at ConcurrentHashMap at java,
and specifically the putIfAbsent method, a typical usage of this method would be:

ConcurrentMap<String,Person>  map = new ConcurrentHashMap<>();
map.putIfAbsent("John",new Person("John"));

The problem is that the Person object is always initialized.
Is there some helper collection (maybe some java framework providing this)
that will give me similar behavior of ConcurrentHashMap, and that will work with a functor or any other mean to construct the value object,
and the construction code (i.e - functor.execute() ) will be called only if the map does not contain a value for the given key?


Solution

  • The only way to do this is to use locking. You can minimise the impact of this by using checking first.

    if(!map.containsKey("John"))
        synchronized(map) {
            if(!map.containsKey("John"))
               map.put("John", new Person("John"));
        }
    

    The reson you need locking is that you need to hold the map while you create the Person to prevent other threads trying to add the same object at the same time. ConcurrentMap doesn't support blocking operations like this directly.

    If you need to minise locking to a specific key you can do the following.

    ConcurrentMap<String, AtomicReference<Person>> map = new ConcurrentHashMap<String, AtomicReference<Person>>();
    
    String name = "John";
    
    AtomicReference<Person> personRef = map.get(name);
    if (personRef == null)
        map.putIfAbsent(name, new AtomicReference<Person>());
    personRef = map.get(name);
    if (personRef.get() == null)
        synchronized (personRef) {
            if (personRef.get() == null)
                // can take a long time without blocking use of other keys.
                personRef.set(new Person(name));
        }
    Person person = personRef.get();