簡體   English   中英

如何在 executorCompletionService 中使用 concurrentHashMap?

[英]How to use concurrentHashMap in executorCompletionService?

我多次搜索數據庫,即使我緩存了一些結果,仍然花費了很長時間。

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 是一個 function 根據startRingendRing和 cacheRingMap 中的緩存搜索數據庫,如果我發現結果在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);
    }
}

當我使用 concurrentHashMap 在 executorCompletionService 中緩存結果時,這個線程是否安全?

ConcurrentHashMap本身是線程安全的,顧名思義(“Concurrent”)。 但是,這並不意味着使用它的代碼是線程安全的。

例如,如果您的代碼執行以下操作:

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
}

由於在此示例中getput不是原子執行的,因此執行此代碼的兩個線程最終可能會首先在緩存中查找相同的鍵,然后在 db.xml 中查找相同的鍵。 它仍然是線程安全的,但我們執行了兩次數據庫查找而不是一次。 但這只是一個簡單的示例,更復雜的緩存邏輯(例如,包括緩存失效和從緩存映射中刪除的邏輯)最終不僅會浪費,而且實際上是不正確的。 這完全取決於 map 的使用方式以及您需要什么保證。 我建議您閱讀ConcurrentHashMap javadoc 看看它能保證什么,不能保證什么。

換了以后會不會跑的快?

這取決於太多需要提前知道的參數。 數據庫將如何處理並發查詢? 有多少查詢? 單個查詢有多快? 等等。最好的了解方法是實際嘗試一下。

附帶說明一下,如果您正在尋找提高性能的方法,您可能想嘗試使用批處理查詢。 然后流程將是在緩存中搜索您需要的所有鍵,收集您需要查找的鍵,然后在一個查詢中將它們一起發送到數據庫。 在許多情況下,單個大型查詢會比一堆較小的查詢運行得更快。

此外,在您的情況下,您應該檢查 map 中的並發查找是否比單線程查找快。 也許僅並行化查詢本身,而不是緩存查找可以在您的情況下產生更好的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM