roger_that
roger_that

Reputation: 9791

Scenario: Why to use ConcurrentHashMap?

Recently I was involved in the discussion where I was given a cache which needs to be implemented to support below operation:

int getData(String key){
     if(cache.get(key) !=null){
             return cache.get(key);
     } else {
         int val = getValueFromDB();  // line no. 5
         cache.put(key, val);        // line no. 6
         return val;
     }

Now the question is, in a multi-threaded scenario, to implement cache, which would you use: HashMap or ConcurrentHashMap?

My ans: ConcurrentHashMap, as it allows read operation on same and different segment and allows write operations only on different segment.

The argument here by lead was, since key is same, multiple threads will execute to line 5 but only one will perform `line no. 6. Since it is a DB call, it needs to executed just once to put the value on cache if not present.

Me: I can make getData sync.

Lead: Then why ConcurrentHashMap? Normal HashMap would also do.

Me: I'll put line no. 5 and line no. 6 inside sync block.

Lead: Then multiple threads would wait at the block. When one thread executes and notifies others, next thread would execute the db call.

Now, How can we achieve this? Basically, we do not want to execute multiple db calls. It should be done by one thread with just one call.

Please advise.

Upvotes: 2

Views: 2816

Answers (2)

Michael
Michael

Reputation: 44200

He's right on pretty much everything. The problem you're having is that you're not taking full advantage of the features ConcurrentHashMap provides.

You're using regular methods of Map - get() and put() - which results in a "check-then-act".

Needless to say, this problem has already been solved: there's a computeIfAbsent method which does pretty much exactly what you need:

int getData(String key){
     return cache.computeIfAbsent(key, k -> getValueFromDB());
}

I had initially suggested to use putIfAbsent but the problem with this is that the getValueFromDB function will be evaluated regardless of whether its required.

Upvotes: 6

bowmore
bowmore

Reputation: 11300

The answer here is to use ConcurrentHashMap's computeIfAbsent(). This method is implemented to get the value for the key from the Map, and if it is absent, to calculate it, given the provided mapping Function. On ConcurrentHashMap it will do this atomically.

So in your case, the function would be implemented to fetch the entry from the DB. As this happens atomically, you're guaranteed for it to happen only once.

Like this :

int getData(String key){
    return cache.computeIfAbsent(key, k -> getValueFromDb());
}

Upvotes: 7

Related Questions