Search code examples
javaconcurrenthashmap

ConcurrentHashMap: Using merge() on a nested concurrentHashMap in Java


I have a concurrentHashMap like this:

ConcurrentHashMap<String, ConcurrentHashMap<Long, Long>> hashMap = new ConcurrentHashMap<>()

I need to update the nested hashmap's value based on the current value if already present. I was currently doing something like this:

 if (hashMap.containsKey("key")) {

        long count = (hashMap.get("key").containsKey(longKey)) ?
                    (hashMap.get("key").get(longKey) + 1l) :
                    1l;

        hashMap.put("key", new ConcurrentHashMap<Long, Long>() {{
            put(longKey, count);
        }});
    }

Basically, check if "key" is present, then check if longKey is present in the nested concurrentHashMap and if yes, all 1l to the existing value. Else, put 1l. If "key" not present, create a new concurrentHashMap with new values.

How can I use merge method https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#merge-K-V-java.util.function.BiFunction- to do the same? Because I want get and update to be atomic.


Solution

  • As I understand the problem, you can do this in a thread-safe manner using the following code:

    Map<Long, Long> longMap =
        hashMap.computeIfAbsent("key", k -> new ConcurrentHashMap<>());
    longMap.merge(longKey, 1L, Long::sum);
    

    You should seriously consider just using plain synchronization. Plain synchronization is much, much easier to get right if you are inexperienced at writing thread-safe code. If you use a Collections.synchronizedMap, for example, you can just do synchronized (map) {...} any time you need to do more than a single method call.