最近我参与了讨论,在那里我获得了一个缓存,需要实现以支持以下操作:
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. 5
和line no. 6
放在同步区内。
导致:然后多个线程将在块中等待。当一个线程执行并通知其他线程时,下一个线程将执行db调用。
现在,我们怎样才能做到这一点?基本上,我们不想执行多个db调用。它应该由一个线程完成,只需一次调用。
请告知。
答案 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
函数将被评估,无论其是否需要。