场景:为什么要使用ConcurrentHashMap?

rog*_*hat 1 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;
     }
Run Code Online (Sandbox Code Playgroud)

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

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

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

我:我可以getData同步.

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

我:我把line no. 5line no. 6同步块内.

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

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

请指教.

bow*_*ore 6

这里的答案是使用ConcurrentHashMap's computeIfAbsent().实现此方法是为了从Map获取键的值,如果不存在,则在给定提供的映射的情况下计算它Function.在ConcurrentHashMap它上面会以原子方式做到这一点.

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

像这样 :

int getData(String key){
    return cache.computeIfAbsent(key, k -> getValueFromDb());
}
Run Code Online (Sandbox Code Playgroud)


Mic*_*ael 5

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

您使用的Map- get()put()- 常规方法会导致“先检查后行动”

不用说,这个问题已经解决:有一种computeIfAbsent方法可以完全满足您的需求:

int getData(String key){
     return cache.computeIfAbsent(key, k -> getValueFromDB());
}
Run Code Online (Sandbox Code Playgroud)

我最初建议使用,putIfAbsent但是这样做的问题是,getValueFromDB无论是否需要该函数,都将对其进行评估。