1. 程式人生 > >1000-ms-HashMap 執行緒安全安全問題

1000-ms-HashMap 執行緒安全安全問題

問題:
HashMap是否是執行緒安全

詳解 http://www.importnew.com/21396.html 有原始碼分析 和程式碼效能比較 CHM效能最好

HashMap不是執行緒安全的;Hashtable執行緒安全,但效率低,因為是Hashtable是使用synchronized的,所有執行緒競爭同一把鎖;而ConcurrentHashMap不僅執行緒安全而且效率高,因為它包含一個segment陣列,將資料分段儲存,給每一段資料配一把鎖,也就是所謂的鎖分段技術。

為什麼執行緒不安全

  1. 如果多個執行緒同時使用put方法新增元素,而且假設正好存在兩個put的key發生了碰撞(hash值一樣),那麼根據HashMap的實現,這兩個key會新增到陣列的同一個位置,這樣最終就會發生其中一個執行緒的put的資料被覆蓋。
  2. 如果多個執行緒同時檢測到元素個數超過陣列大小*loadFactor,這樣就會發生多個執行緒同時對Node陣列進行擴容,都在重新計算元素位置以及複製資料,但是最終只有一個執行緒擴容後的陣列會賦給table,也就是說其他執行緒的都會丟失,並且各自執行緒put的資料也丟失。

    關於HashMap執行緒不安全這一點,《Java併發程式設計的藝術》一書中是這樣說的:
    HashMap在併發執行put操作時會引起死迴圈,導致CPU利用率接近100%。因為多執行緒會導致HashMap的Node連結串列形成環形資料結構,一旦形成環形資料結構,Node的next節點永遠不為空,就會在獲取Node時產生死迴圈。

如何執行緒安全的使用HashMap

使用 Hashtabl ConcurrentHashMap Synchronized Map

//Hashtable
Map<String, String> hashtable = new Hashtable<>();
 
//synchronizedMap
Map<String, String> synchronizedHashMap = Collections.synchronizedMap(new HashMap<String, String>());
 
//ConcurrentHashMap
Map<String, String> concurrentHashMap = new ConcurrentHashMap<>();

Hashtable如何保證安全的?
看原始碼發現 get(Object key)方法和put(Object key)方法,都加了synchronized
效率比較低

SynchronizedMap

看原始碼也是使用了大量的synchronized ,來保證安全

ConcurrentHashMap

ConcurrentHashMap(以下簡稱CHM)是JUC包中的一個類,Spring的原始碼中有很多使用CHM的地方。之前已經翻譯過一篇關於ConcurrentHashMap的部落格,如何在java中使用ConcurrentHashMap,裡面介紹了CHM在Java中的實現,CHM的一些重要特性和什麼情況下應該使用CHM。需要注意的是,上面部落格是基於Java 7的,和8有區別,在8中CHM摒棄了Segment(鎖段)的概念,而是啟用了一種全新的方式實現,利用CAS演算法,有時間會重新總結一下。