我在数据库中搜索了很多次,即使我缓存了一些结果,但仍然花费了很长时间。
List<Map<Long, Node>> aNodeMapList = new ArrayList<>();
Map<String, List<Map<String, Object>>> cacheRingMap = new ConcurrentHashMap<>();
for (Ring startRing : startRings) {
for (Ring endRing : endRings) {
Map<String, Object> nodeMapResult = getNodeMapResult(startRing, endRing, cacheRingMap);
Map<Long, Node> nodeMap = (Map<Long, Node>) nodeMapResult.get("nodeMap");
if (nodeMap.size() > 0) {
aNodeMapList.add(nodeMap);
}
}
}
getNodeMapResult是根据startRing
、endRing
查找数据库的函数,并缓存在cacheRingMap
中,下次可能不需要搜索数据库,如果我发现结果存在于
cacheRingMap
。
领导告诉我可以使用多线程技术。所以我把它改为executorCompletionService,但现在我有一个问题,当我使用concurrentHashMap在executorCompletionService中缓存结果时,这个线程安全吗? 改了之后跑得快吗?
int totalThreadCount = startRings.size() * endRings.size();
ExecutorService threadPool2 = Executors.newFixedThreadPool(totalThreadCount > 4 ? 4 : 2);
CompletionService<Map<String, Object>> completionService = new ExecutorCompletionService<Map<String, Object>>(threadPool2);
for (Ring startRing : startRings) {
for (Ring endRing : endRings) {
completionService.submit(new Callable<Map<String, Object>>() {
@Override
public Map<String, Object> call() throws Exception {
return getNodeMapResult(startRing, endRing, cacheRingMap);
}
});
}
}
for (int i = 0; i < totalThreadCount; i++) {
Map<String, Object> nodeMapResult = completionService.take().get();
Map<Long, Node> nodeMap = (Map<Long, Node>) nodeMapResult.get("nodeMap");
if (nodeMap.size() > 0) {
aNodeMapList.add(nodeMap);
}
}
最佳答案
Is this thread safe when I use concurrentHashMap to cache result in executorCompletionService?
ConcurrentHashMap 本身是线程安全的,正如其名称所暗示的那样(“并发”)。但是,这并不意味着使用它的代码是线程安全的。
例如,如果您的代码执行以下操作:
SomeObject object = cacheRingMap.get(someKey); //get from cache
if (object == null){ //oh-oh, cache miss
object = getObjectFromDb(someKey); //get from the db
cacheRingMap.put(someKey, object); //put in cache for next time
}
由于在此示例中 get
和 put
不是自动执行的,因此执行此代码的两个线程最终可能会首先在缓存中查找相同的键,然后在数据库中。它仍然是线程安全的,但我们执行了两次数据库查找,而不是一次。但这只是一个简单的例子,更复杂的缓存逻辑(比如包括缓存失效和从缓存映射中删除的逻辑)最终可能不仅是浪费,而且实际上是不正确的。这完全取决于 map 的使用方式以及您需要从中获得什么保证。我建议您阅读ConcurrentHashMap javadoc 。看看它能保证什么,不能保证什么。
Will it run fast after I change?
这取决于太多参数,无法提前了解。数据库如何处理并发查询?有多少查询?单个查询的速度有多快?等等。最好的了解方法就是实际尝试一下。
顺便说一句,如果您正在寻找提高性能的方法,您可能需要尝试使用批量查询。然后,流程将在缓存中搜索您需要的所有键,收集您需要查找的键,然后在单个查询中将它们全部发送到数据库。在许多情况下,单个大型查询比一堆较小的查询运行得更快。
此外,您应该检查映射中的并发查找是否比您的情况下的单线程查找更快。也许仅并行化查询本身而不并行化缓存查找可以在您的情况下产生更好的结果。
关于java - 如何在executorCompletionService中使用concurrentHashMap?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58398901/