[英]How does ConcurrentHashMap work internally?
我正在閱讀有關 Java 並發的 Oracle 官方文檔,我想知道返回的Collection
之間有什么區別
public static <T> Collection<T> synchronizedCollection(Collection<T> c);
並使用例如
ConcurrentHashMap
。 我假設我在HashMap
上使用synchronizedCollection(Collection<T> c)
。 我知道一般來說,同步集合本質上只是我的HashMap
的裝飾器,因此很明顯ConcurrentHashMap
的內部結構有所不同。 你有關於這些實現細節的一些信息嗎?
編輯:我意識到源代碼是公開可用的: ConcurrentHashMap.java
我會閱讀ConcurrentHashMap的來源,因為它的細節相當復雜。 總之它有
ConcurrentHashMap
與java.util.HashTable
類非常相似,除了ConcurrentHashMap
提供比HashTable
或synchronizedMap
更好的並發性。 ConcurrentHashMap
在您讀取 Map 時不會鎖定它。 此外, ConcurrentHashMap
在寫入時不會鎖定整個Map
。 它只在內部鎖定正在寫入的Map
部分。
另一個區別是,如果ConcurrentHashMap
在迭代時發生更改,則 ConcurrentHashMap 不會拋出ConcurrentModificationException
。 Iterator
並非設計為由多個線程使用,而synchronizedMap
可能會拋出ConcurrentModificationException
這篇文章幫助我理解了為什么 ConcurrentHashMap 比 Hashtable 更好並且和 HashMap 一樣好
Hashtable 提供對其條目的並發訪問,但需要注意的是,整個映射被鎖定以執行任何類型的操作。 雖然這種開銷在正常負載下的 web 應用程序中是可以忽略的,但在重負載下,它可能會導致響應時間延遲和服務器無緣無故地負擔過重。
這就是 ConcurrentHashMap 的用武之地。它們提供了 Hashtable 的所有功能,並且性能幾乎與 HashMap 一樣好。 ConcurrentHashMap 通過一個非常簡單的機制來實現這一點。 該集合默認維護一個包含 16 個鎖的列表,而不是地圖范圍的鎖,每個鎖用於保護(或鎖定)地圖的單個存儲桶。 這實際上意味着 16 個線程可以一次修改集合(只要它們都在不同的存儲桶上工作)。 事實上,這個集合沒有執行鎖定整個地圖的操作。 集合的並發級別,可以在不阻塞的情況下同時修改它的線程數,可以增加。 然而,更高的數字意味着維護這個鎖列表的開銷更大。
Hashtable
的“可擴展性問題”在Collections.synchronizedMap(Map)
以完全相同的方式存在——它們使用非常簡單的同步,這意味着只有一個線程可以同時訪問映射。
當您進行簡單的插入和查找時,這不是什么大問題(除非您非常密集地執行此操作),但是當您需要遍歷整個 Map 時會成為一個大問題,這對於大型 Map 可能需要很長時間 - 而一個線程這樣做,所有其他線程如果要插入或查找任何內容都必須等待。
ConcurrentHashMap
使用非常復雜的技術來減少同步的需要,並允許多個線程在沒有同步的情況下並行讀取訪問,更重要的是,它提供了一個不需要同步的迭代器,甚至允許在交互期間修改 Map(盡管它不保證是否會返回在迭代期間插入的元素)。
synchronizedCollection()返回的是一個對象,其所有方法都在this上同步,因此此類包裝器上的所有並發操作都被序列化。 ConcurrentHashMap 是一個真正的並發容器,具有優化的細粒度鎖定以保持盡可能低的爭用。 看看源代碼,你會看到它里面的內容。
ConcurrentHashMap 實現了提供並發性的 ConcurrentMap。 在內部,它的迭代器被設計為一次僅由一個線程使用,以保持同步。 此映射在並發中被廣泛使用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.