ConcurrentHashMap && Hashtable#
ConcurrentHashMap 是如何實現線程安全的 ?#
JDK1.5 中的實現#
使用
Segment(extends ReentrantLock)
來實現
使用分段鎖技術
, 將 ConcurrentHashMap 將鎖一段一段的存儲,然後給每一段數據配一把鎖(segment),當一個線程占用一把鎖(segment)訪問其中一段數據的時候,其他段的數據也能被其它的線程訪問,默認分配 16 個 segment, 默認比 Hashtable 效率提高 16 倍
JDK1.8 中的實現#
采用
CAS
和synchronized
來保證並發安全
JDK8 中的實現也是鎖分離的思想,它把鎖分的比segment(JDK1.5)
更細一些,只要 hash 不衝突,就不會出現並發獲得鎖的情況。它首先使用無鎖操作CAS
插入頭結點,如果插入失敗,說明已經有別的線程插入頭結點了,再次循環進行操作 (類似自旋鎖)。如果頭結點已經存在,則通過synchronized獲得頭結點鎖
,進行後續的操作,性能比 segment 分段鎖又再次提升
Hashtable#
Hashtable 也是線程安全的一種鍵值對的數據結構
和 HashMap 比較:#
- Hashtable 在 JDK1.0 就有了,HashMap 產生於 JDK1.2
- Hashtable 繼承自 Dictionary 類 (已廢棄), HashMap 是繼承自 AbstractMap 類
- Hashtable 既不支持 Null key 也不支持 Null value,HashMap 中,null 可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值為 null
- Hashtable 是線程安全的,它的每個方法中都加入了 Synchronize 方法,HashMap 不是線程安全的
- Hashtable、HashMap 都使用了 Iterator,不過由於歷史原因,Hashtable 還使用了 Enumeration 的方式
- Hashtable 默認的初始大小為 11,之後每次擴充,容量變為原來的 2n+1。HashMap 默認的初始化大小為 16。之後每次擴充,容量變為原來的 2 倍
- 計算 hash 值的方法不同: Hashtable 直接使用對象的 hashCode, 而 HashMap 還使用了擾動函數處理
和 Collections.synchronizedMap () 的區別#
synchronizedMap
是 Collections 的私有靜態內部類,可以通過Collecitons.synchronizedMap(Map)
方法獲取一個 synchronizedMap 向上轉型為 Map 對象
對比分析:
- Hashtable 是對所有方法通過 synchronized 關鍵字加鎖
- 有一個 Object 類型 mutext 互斥對象成員,對存在線程安全的方法使用 synchronize 關鍵字對 mutex 進行加鎖