场景:为什么要用ConcurrentHashMap?
Scenario: Why to use 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?
我的回答:ConcurrentHashMap,因为它允许在相同和不同的段上进行读取操作,并且只允许在不同的段上进行写入操作。
lead 在这里的论点是,由于键相同,多个线程将执行到 line 5
但只有一个线程将执行 `line no. 6. 由于是数据库调用,如果不存在,只需要执行一次,将值放入缓存。
我:我可以getData
同步。
Lead:那为什么是ConcurrentHashMap?普通的 HashMap 也可以。
我:我会把line no. 5
和line no. 6
放在同步块里。
Lead:那么多个线程会在block处等待。当一个线程执行并通知其他线程时,下一个线程将执行数据库调用。
现在,我们怎样才能做到这一点?基本上,我们不想执行多个数据库调用。一个线程调用一次就可以完成。
请指教
这里的答案是使用ConcurrentHashMap
的computeIfAbsent()
。实现此方法是为了从 Map 中获取键的值,如果不存在,则根据提供的映射 Function
计算它。在 ConcurrentHashMap
上,它将自动执行此操作。
因此,在您的情况下,将实施该函数以从数据库中获取条目。由于这是自动发生的,因此可以保证它只会发生一次。
像这样:
int getData(String key){
return cache.computeIfAbsent(key, k -> getValueFromDb());
}
他几乎在所有事情上都是对的。您遇到的问题是您没有充分利用 ConcurrentHashMap
提供的功能。
您使用的是 Map
- get()
和 put()
的常规方法 - 结果是 "check-then-act".
不用说,这个问题已经解决了:有一个 computeIfAbsent
方法几乎可以满足您的需要:
int getData(String key){
return cache.computeIfAbsent(key, k -> getValueFromDB());
}
我最初建议使用 putIfAbsent
但问题是 getValueFromDB
函数将被评估,无论它是否需要。
最近我参与了一个讨论,我得到了一个需要实现以支持以下操作的缓存:
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?
我的回答:ConcurrentHashMap,因为它允许在相同和不同的段上进行读取操作,并且只允许在不同的段上进行写入操作。
lead 在这里的论点是,由于键相同,多个线程将执行到 line 5
但只有一个线程将执行 `line no. 6. 由于是数据库调用,如果不存在,只需要执行一次,将值放入缓存。
我:我可以getData
同步。
Lead:那为什么是ConcurrentHashMap?普通的 HashMap 也可以。
我:我会把line no. 5
和line no. 6
放在同步块里。
Lead:那么多个线程会在block处等待。当一个线程执行并通知其他线程时,下一个线程将执行数据库调用。
现在,我们怎样才能做到这一点?基本上,我们不想执行多个数据库调用。一个线程调用一次就可以完成。
请指教
这里的答案是使用ConcurrentHashMap
的computeIfAbsent()
。实现此方法是为了从 Map 中获取键的值,如果不存在,则根据提供的映射 Function
计算它。在 ConcurrentHashMap
上,它将自动执行此操作。
因此,在您的情况下,将实施该函数以从数据库中获取条目。由于这是自动发生的,因此可以保证它只会发生一次。
像这样:
int getData(String key){
return cache.computeIfAbsent(key, k -> getValueFromDb());
}
他几乎在所有事情上都是对的。您遇到的问题是您没有充分利用 ConcurrentHashMap
提供的功能。
您使用的是 Map
- get()
和 put()
的常规方法 - 结果是 "check-then-act".
不用说,这个问题已经解决了:有一个 computeIfAbsent
方法几乎可以满足您的需要:
int getData(String key){
return cache.computeIfAbsent(key, k -> getValueFromDB());
}
我最初建议使用 putIfAbsent
但问题是 getValueFromDB
函数将被评估,无论它是否需要。