场景:为什么要使用ConcurrentHashMap?

时间:2017-08-31 08:26:28

标签: java multithreading hashmap concurrenthashmap

最近我参与了讨论,在那里我获得了一个缓存,需要实现以支持以下操作:

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;
     }

现在的问题是,在一个多线程场景中,实现缓存,你会使用:HashMap或ConcurrentHashMap?

我的ans:ConcurrentHashMap,因为它允许在相同和不同的段上进行读操作,并且只允许在不同的段上进行写操作。

这里由lead引用的论点是,因为key是相同的,所以多个线程将执行到line 5,但只有一个执行`line no。 6.由于它是一个DB调用,它只需执行一次即可将值放在缓存中(如果不存在)。

我:我可以getData同步。

导语:那为什么ConcurrentHashMap?普通的HashMap也可以。

我:我将line no. 5line no. 6放在同步区内。

导致:然后多个线程将在块中等待。当一个线程执行并通知其他线程时,下一个线程将执行db调用。

现在,我们怎样才能做到这一点?基本上,我们不想执行多个db调用。它应该由一个线程完成,只需一次调用。

请告知。

2 个答案:

答案 0 :(得分:6)

这里的答案是使用ConcurrentHashMap的{​​{3}}。实现此方法是为了从Map获取键的值,如果不存在,则在给定提供的映射Function的情况下计算它。在ConcurrentHashMap,它将以原子方式执行此操作。

因此,在您的情况下,将实现该函数以从DB中获取条目。由于这是以原子方式发生的,因此您只能保证它只发生一次。

像这样:

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

答案 1 :(得分:4)

几乎所有事情他都是对的。您遇到的问题是您没有充分利用ConcurrentHashMap提供的功能。

您正在使用Map - get()put()的常规方法,这会产生"check-then-act"

毋庸置疑,这个问题已经解决了:computeIfAbsent方法可以完全满足您的需求:

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

我最初建议使用putIfAbsent,但问题是getValueFromDB函数将被评估,无论其是否需要。