簡體   English   中英

為什么ConcurrentHashMap中的computeIfAbsent()方法行為不一致?

[英]Why is the computeIfAbsent() method in ConcurrentHashMap behaving inconsistently?

我在Apache Tomcat 9的調用一個Java 8 Web應用程序運行ConcurrentHashMapcomputeIfAbsent()方法沒有返回或時間過長返回。

在下面給出的代碼中,打印“ 添加到地圖 ”行,並且在某些情況下根本不打印“ Map: ”行,就像執行的線程被捕獲在方法中一樣。 一旦被捕獲,對具有相同id的相同方法的任何后續調用也會卡住並且永遠不會返回,而具有不同id調用立即返回。 在另一個具有不同id實例上進行測試,在2分鍾后返回computeIfAbsent()方法。 在測試時執行代碼的最大並發調用數僅為20左右。 根據我的理解, computeIfAbsent()是線程安全的。 這有什么不對?

private Map<String, Map<String, SomeClass>> aMap = new ConcurrentHashMap<>();
LOGGER.debug("Adding to Map");
Map<String, SomeClass> m = aMap
            .computeIfAbsent(id, k -> Collections.synchronizedMap(new HashMap<>()));
LOGGER.debug("Map : " + m);

對具有相同id的相同方法的任何后續調用也會被卡住並且在具有不同id的調用立即返回時永遠不會返回?

是,如果計算正在進行,則將阻止該ID的任何后續計算調用

如果指定的鍵尚未與值關聯,則嘗試使用給定的映射函數計算其值,並將其輸入此映射,除非為null。 整個方法調用是以原子方式執行的, 因此每個鍵最多應用一次該函數。 在計算正在進行時可能會阻止其他線程對此映射進行的某些嘗試更新操作,因此計算應該簡短,並且不得嘗試更新此映射的任何其他映射。

在測試時執行代碼的最大並發調用數僅為20左右。 據我所知?

不,這完全取決於該地圖中有多少可用的存儲桶

ConcurrentHashMap中 ,任何數量的線程都可以執行檢索操作,但是對於對象的更新,線程必須鎖定線程想要操作的特定段。這種類型的鎖定機制稱為段鎖定或桶鎖定。 因此,在時間16可以執行更新操作

computeIfAbsent()是線程安全的嗎?

是的,它是線程安全的ConcurrentHashMap

一個哈希表,支持檢索的完全並發和更新的高預期並發性。 該類遵循與Hashtable相同的功能規范,並包括與Hashtable的每個方法相對應的方法版本。 但是,即使所有操作都是線程安全的,檢索操作也不需要鎖定,並且不支持以阻止所有訪問的方式鎖定整個表。 在依賴於線程安全但不依賴於其同步細節的程序中,此類可與Hashtable完全互操作。

老實說,我不是那個設計和實現ConcurrentHashMap ,但通過互聯網,我找到了一篇關於java 8 ConcurrentHashMap改進的文章,我認為這可能會導致第一次調用的延遲。

延遲表初始化,在首次使用之前最小化占用空間

暫無
暫無

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

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